Inconsummate numbers in base 10: Difference between revisions
m (Python example) |
(→{{header|Wren}}: Added a Python translation.) |
||
Line 132: | Line 132: | ||
One thousandth: 6,996 |
One thousandth: 6,996 |
||
</pre> |
|||
Alternatively and more generally: |
|||
{{trans|Python}} |
|||
Though I think the Python version is in fact wrong for the 100,000th number since if you enumerate up to 10,000 you get the 10,000th inconsummate number to be 42,171 rather than 59,853. |
|||
The problem seems to be that the minimum divisor for (say) 6 digit numbers is not 999999/54 = 18518 but 109999/37 = 2972. I've corrected for that in the following translation. |
|||
<syntaxhighlight lang="ecmascript">import "./math" for Int, Nums |
|||
import "./fmt" for Fmt |
|||
var generateInconsummate = Fn.new { |maxWanted| |
|||
var minDigitSums = (2..14).map { |i| [10.pow(i), ((10.pow(i-2) * 11 - 1) / (9 * i - 17)).floor] } |
|||
var limit = Nums.min(minDigitSums.where { |p| p[1] > maxWanted }.map { |p| p[0] }) |
|||
var arr = List.filled(limit, 0) |
|||
arr[0] = 1 |
|||
for (dividend in 1...limit) { |
|||
var ds = Int.digitSum(dividend) |
|||
var quo = (dividend/ds).floor |
|||
var rem = dividend % ds |
|||
if (rem == 0 && quo < limit) arr[quo] = 1 |
|||
} |
|||
for (j in 0...arr.count) { |
|||
if (arr[j] == 0) Fiber.yield(j) |
|||
} |
|||
} |
|||
var gi = Fiber.new(generateInconsummate) |
|||
var incons = List.filled(50, 0) |
|||
var incons1k |
|||
var incons10k |
|||
var incons100k |
|||
System.print("First 50 inconsummate numbers in base 10:") |
|||
for (i in 1..100000) { |
|||
var j = gi.call(100000) |
|||
if (i <= 50) { |
|||
incons[i-1] = j |
|||
} else if (i == 1000) { |
|||
incons1k = j |
|||
} else if (i == 10000) { |
|||
incons10k = j |
|||
} else if (i == 100000) { |
|||
incons100k = j |
|||
} |
|||
} |
|||
Fmt.tprint("$3d", incons, 10) |
|||
Fmt.print("\nOne thousandth $,d", incons1k) |
|||
Fmt.print("Ten thousandth $,d", incons10k) |
|||
Fmt.print("100 thousandth $,d", incons100k)</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
First 50 inconsummate numbers in base 10: |
|||
62 63 65 75 84 95 161 173 195 216 |
|||
261 266 272 276 326 371 372 377 381 383 |
|||
386 387 395 411 416 422 426 431 432 438 |
|||
441 443 461 466 471 476 482 483 486 488 |
|||
491 492 493 494 497 498 516 521 522 527 |
|||
One thousandth 6,996 |
|||
Ten thousandth 59,853 |
|||
100 thousandth 536,081 |
|||
</pre> |
</pre> |
Revision as of 09:59, 28 September 2022
A consummate number is a non-negative integer that can be formed by some integer N divided by the the digital sum of N.
- For instance
47 is a consummate number.
846 / (8 + 4 + 6) = 47
On the other hand, there are integers that can not be formed by a ratio of any integer over its digital sum. These numbers are known as inconsummate numbers.
62 is an inconsummate number. There is no integer ratio of an integer to its digital sum that will result in 62.
The base that a number is expressed in will affect whether it is inconsummate or not. This task will be restricted to base 10.
- Task
- Write a routine to find inconsummate numbers in base 10;
- Use that routine to find and display the first fifty inconsummate numbers.
- Stretch
- Use that routine to find and display the one thousandth inconsummate number.
- See also
Python
''' Rosetta code rosettacode.org/wiki/Inconsummate_numbers_in_base_10 '''
def digitalsum(num):
''' Return sum of digits of a number in base 10 '''
return sum(int(d) for d in str(num))
def generate_inconsummate(max_wanted):
''' generate the series of inconsummate numbers up to max_wanted '''
minimum_digitsums = [(10**i, int((10**i - 1) / (9 * i)))
for i in range(1, 15)]
limit = min(p[0] for p in minimum_digitsums if p[1] > max_wanted)
arr = [1] + [0] * (limit - 1)
for dividend in range(1, limit):
quo, rem = divmod(dividend, digitalsum(dividend))
if rem == 0 and quo < limit:
arr[quo] = 1
for j, flag in enumerate(arr):
if flag == 0:
yield j
for i, n in enumerate(generate_inconsummate(100000)):
if i < 50:
print(f'{n:6}', end='\n' if (i + 1) % 10 == 0 else '')
elif i == 999:
print('\nThousandth inconsummate number:', n)
elif i == 9999:
print('\nTen-thousanth inconsummate number:', n)
elif i == 99999:
print('\nHundred-thousanth inconsummate number:', n)
break
- Output:
62 63 65 75 84 95 161 173 195 216 261 266 272 276 326 371 372 377 381 383 386 387 395 411 416 422 426 431 432 438 441 443 461 466 471 476 482 483 486 488 491 492 493 494 497 498 516 521 522 527 Thousandth inconsummate number: 6996 Ten-thousanth inconsummate number: 59853 Hundred-thousanth inconsummate number: 375410
Raku
Not really pleased with this entry. It works, but seems inelegant.
my $upto = 1000;
my @ratios = unique (^∞).race.map({($_ / .comb.sum).narrow})[^($upto²)].grep: Int;
my @incons = (sort keys (1..$upto * 10) (-) @ratios)[^$upto];
put "First fifty inconsummate numbers (in base 10):\n" ~ @incons[^50]».fmt("%3d").batch(10).join: "\n";
put "\nOne thousandth: " ~ @incons[999]
- Output:
First fifty inconsummate numbers (in base 10): 62 63 65 75 84 95 161 173 195 216 261 266 272 276 326 371 372 377 381 383 386 387 395 411 416 422 426 431 432 438 441 443 461 466 471 476 482 483 486 488 491 492 493 494 497 498 516 521 522 527 One thousandth: 6996
Wren
It appears to be more than enough to calculate ratios for all numbers up to 999,999 (which only takes about 0.4 seconds on my machine) to be sure of finding the 1,000th inconsummate number.
import "./math" for Int
import "./fmt" for Fmt
// Maximum ratio for 6 digit numbers is 100,000
var cons = List.filled(100001, false)
for (i in 1..999999) {
var ds = Int.digitSum(i)
var ids = i/ds
if (ids.isInteger) cons[ids] = true
}
var incons = []
for (i in 1...cons.count) {
if (!cons[i]) incons.add(i)
}
System.print("First 50 inconsummate numbers in base 10:")
Fmt.tprint("$3d", incons[0..49], 10)
Fmt.print("\nOne thousandth: $,d", incons[999])
- Output:
First 50 inconsummate numbers in base 10: 62 63 65 75 84 95 161 173 195 216 261 266 272 276 326 371 372 377 381 383 386 387 395 411 416 422 426 431 432 438 441 443 461 466 471 476 482 483 486 488 491 492 493 494 497 498 516 521 522 527 One thousandth: 6,996
Alternatively and more generally:
Though I think the Python version is in fact wrong for the 100,000th number since if you enumerate up to 10,000 you get the 10,000th inconsummate number to be 42,171 rather than 59,853.
The problem seems to be that the minimum divisor for (say) 6 digit numbers is not 999999/54 = 18518 but 109999/37 = 2972. I've corrected for that in the following translation.
import "./math" for Int, Nums
import "./fmt" for Fmt
var generateInconsummate = Fn.new { |maxWanted|
var minDigitSums = (2..14).map { |i| [10.pow(i), ((10.pow(i-2) * 11 - 1) / (9 * i - 17)).floor] }
var limit = Nums.min(minDigitSums.where { |p| p[1] > maxWanted }.map { |p| p[0] })
var arr = List.filled(limit, 0)
arr[0] = 1
for (dividend in 1...limit) {
var ds = Int.digitSum(dividend)
var quo = (dividend/ds).floor
var rem = dividend % ds
if (rem == 0 && quo < limit) arr[quo] = 1
}
for (j in 0...arr.count) {
if (arr[j] == 0) Fiber.yield(j)
}
}
var gi = Fiber.new(generateInconsummate)
var incons = List.filled(50, 0)
var incons1k
var incons10k
var incons100k
System.print("First 50 inconsummate numbers in base 10:")
for (i in 1..100000) {
var j = gi.call(100000)
if (i <= 50) {
incons[i-1] = j
} else if (i == 1000) {
incons1k = j
} else if (i == 10000) {
incons10k = j
} else if (i == 100000) {
incons100k = j
}
}
Fmt.tprint("$3d", incons, 10)
Fmt.print("\nOne thousandth $,d", incons1k)
Fmt.print("Ten thousandth $,d", incons10k)
Fmt.print("100 thousandth $,d", incons100k)
- Output:
First 50 inconsummate numbers in base 10: 62 63 65 75 84 95 161 173 195 216 261 266 272 276 326 371 372 377 381 383 386 387 395 411 416 422 426 431 432 438 441 443 461 466 471 476 482 483 486 488 491 492 493 494 497 498 516 521 522 527 One thousandth 6,996 Ten thousandth 59,853 100 thousandth 536,081