Humble numbers
Humble numbers are positive integers which have no prime factors > 7.
You are encouraged to solve this task according to the task description, using any language you may know.
Humble numbers are also called 7-smooth numbers, and sometimes called highly composite,
although this conflicts with another meaning of highly composite numbers.
Another way to express the above is:
humble = 2i × 3j × 5k × 7m
where i, j, k, m ≥ 0
- Task
-
- show the first 50 humble numbers (in a horizontal list)
- show the number of humble numbers that have x decimal digits for all x's up to n (inclusive).
- show (as many as feasible or reasonable for above) on separate lines
- show all output here on this page
- Related tasks
- References
Ada
<lang Ada>with Ada.Text_IO;
procedure Show_Humble is
type Positive is range 1 .. 2**63 - 1; First : constant Positive := Positive'First; Last : constant Positive := 999_999_999;
function Is_Humble (I : in Positive) return Boolean is begin if I <= 1 then return True; elsif I mod 2 = 0 then return Is_Humble (I / 2); elsif I mod 3 = 0 then return Is_Humble (I / 3); elsif I mod 5 = 0 then return Is_Humble (I / 5); elsif I mod 7 = 0 then return Is_Humble (I / 7); else return False; end if; end Is_Humble;
subtype Digit_Range is Natural range First'Image'Length - 1 .. Last'Image'Length - 1; Digit_Count : array (Digit_Range) of Natural := (others => 0);
procedure Count_Humble_Digits is use Ada.Text_IO; Humble_Count : Natural := 0; Len : Natural; begin Put_Line ("The first 50 humble numbers:"); for N in First .. Last loop if Is_Humble (N) then Len := N'Image'Length - 1; Digit_Count (Len) := Digit_Count (Len) + 1;
if Humble_Count < 50 then Put (N'Image); Put (" "); end if; Humble_Count := Humble_Count + 1; end if; end loop; New_Line (2); end Count_Humble_Digits;
procedure Show_Digit_Counts is package Natural_IO is new Ada.Text_IO.Integer_IO (Natural); use Ada.Text_IO; use Natural_IO;
Placeholder : String := "Digits Count"; Image_Digit : String renames Placeholder (1 .. 6); Image_Count : String renames Placeholder (8 .. Placeholder'Last); begin Put_Line ("The digit counts of humble numbers:"); Put_Line (Placeholder); for Digit in Digit_Count'Range loop Put (Image_Digit, Digit); Put (Image_Count, Digit_Count (Digit)); Put_Line (Placeholder); end loop; end Show_Digit_Counts;
begin
Count_Humble_Digits; Show_Digit_Counts;
end Show_Humble;</lang>
- Output:
The first 50 humble numbers: 1 2 3 4 5 6 7 8 9 10 12 14 15 16 18 20 21 24 25 27 28 30 32 35 36 40 42 45 48 49 50 54 56 60 63 64 70 72 75 80 81 84 90 96 98 100 105 108 112 120 The digit counts of humble numbers: Digits Count 1 9 2 36 3 95 4 197 5 356 6 579 7 882 8 1272 9 1767
C
<lang C>#include <limits.h>
- include <stdbool.h>
- include <stdio.h>
- include <string.h>
bool isHumble(int i) {
if (i <= 1) return true; if (i % 2 == 0) return isHumble(i / 2); if (i % 3 == 0) return isHumble(i / 3); if (i % 5 == 0) return isHumble(i / 5); if (i % 7 == 0) return isHumble(i / 7); return false;
}
int main() {
int limit = SHRT_MAX; int humble[16]; int count = 0; int num = 1; char buffer[16];
memset(humble, 0, sizeof(humble));
for (; count < limit; num++) { if (isHumble(num)) { size_t len; sprintf_s(buffer, sizeof(buffer), "%d", num); len = strlen(buffer); if (len >= 16) { break; } humble[len]++;
if (count < 50) { printf("%d ", num); } count++; } } printf("\n\n");
printf("Of the first %d humble numbers:\n", count); for (num = 1; num < 10; num++) { printf("%5d have %d digits\n", humble[num], num); }
return 0;
}</lang>
- Output:
1 2 3 4 5 6 7 8 9 10 12 14 15 16 18 20 21 24 25 27 28 30 32 35 36 40 42 45 48 49 50 54 56 60 63 64 70 72 75 80 81 84 90 96 98 100 105 108 112 120 Of the first 32767 humble numbers: 9 have 1 digits 36 have 2 digits 95 have 3 digits 197 have 4 digits 356 have 5 digits 579 have 6 digits 882 have 7 digits 1272 have 8 digits 1767 have 9 digits
C++
<lang cpp>#include <iomanip>
- include <iostream>
- include <map>
- include <sstream>
bool isHumble(int i) {
if (i <= 1) return true; if (i % 2 == 0) return isHumble(i / 2); if (i % 3 == 0) return isHumble(i / 3); if (i % 5 == 0) return isHumble(i / 5); if (i % 7 == 0) return isHumble(i / 7); return false;
}
auto toString(int n) {
std::stringstream ss; ss << n; return ss.str();
}
int main() {
auto limit = SHRT_MAX; std::map<int, int> humble; auto count = 0; auto num = 1;
while (count < limit) { if (isHumble(num)) { auto str = toString(num); auto len = str.length(); auto it = humble.find(len);
if (it != humble.end()) { it->second++; } else { humble[len] = 1; }
if (count < 50) std::cout << num << ' '; count++; } num++; } std::cout << "\n\n";
std::cout << "Of the first " << count << " humble numbers:\n"; num = 1; while (num < humble.size() - 1) { auto it = humble.find(num); if (it != humble.end()) { auto c = *it; std::cout << std::setw(5) << c.second << " have " << std::setw(2) << num << " digits\n"; num++; } else { break; } }
return 0;
}</lang>
- Output:
1 2 3 4 5 6 7 8 9 10 12 14 15 16 18 20 21 24 25 27 28 30 32 35 36 40 42 45 48 49 50 54 56 60 63 64 70 72 75 80 81 84 90 96 98 100 105 108 112 120 Of the first 32767 humble numbers: 9 have 1 digits 36 have 2 digits 95 have 3 digits 197 have 4 digits 356 have 5 digits 579 have 6 digits 882 have 7 digits 1272 have 8 digits 1767 have 9 digits
D
<lang d>import std.conv; import std.stdio;
bool isHumble(int i) {
if (i <= 1) return true; if (i % 2 == 0) return isHumble(i / 2); if (i % 3 == 0) return isHumble(i / 3); if (i % 5 == 0) return isHumble(i / 5); if (i % 7 == 0) return isHumble(i / 7); return false;
}
void main() {
auto limit = short.max; int[int] humble; auto count = 0; auto num = 1;
while (count < limit) { if (isHumble(num)) { auto str = num.to!string; auto len = str.length; humble[len]++; if (count < 50) write(num, ' '); count++; } num++; } writeln('\n');
writeln("Of the first ", count, " humble numbers:"); num = 1; while (num < humble.length - 1) { if (num in humble) { auto c = humble[num]; writefln("%5d have %2d digits", c, num); num++; } else { break; } }
}</lang>
- Output:
1 2 3 4 5 6 7 8 9 10 12 14 15 16 18 20 21 24 25 27 28 30 32 35 36 40 42 45 48 49 50 54 56 60 63 64 70 72 75 80 81 84 90 96 98 100 105 108 112 120 Of the first 32767 humble numbers: 9 have 1 digits 36 have 2 digits 95 have 3 digits 197 have 4 digits 356 have 5 digits 579 have 6 digits 882 have 7 digits 1272 have 8 digits 1767 have 9 digits
Factor
<lang factor>USING: accessors assocs combinators deques dlists formatting fry generalizations io kernel make math math.functions math.order prettyprint sequences tools.memory.private ; IN: rosetta-code.humble-numbers
TUPLE: humble-iterator 2s 3s 5s 7s digits
{ #digits initial: 1 } { target initial: 10 } ;
- <humble-iterator> ( -- humble-iterator )
humble-iterator new 1 1dlist >>2s 1 1dlist >>3s 1 1dlist >>5s 1 1dlist >>7s H{ } clone >>digits ;
- enqueue ( n humble-iterator -- )
{ [ [ 2 * ] [ 2s>> ] ] [ [ 3 * ] [ 3s>> ] ] [ [ 5 * ] [ 5s>> ] ] [ [ 7 * ] [ 7s>> ] ] } [ bi* push-back ] map-compose 2cleave ;
- count-digits ( humble-iterator n -- )
[ over target>> >= [ [ 1 + ] change-#digits [ 10 * ] change-target ] when ] [ drop 1 swap [ #digits>> ] [ digits>> ] bi at+ ] bi ;
- ?pop ( 2s 3s 5s 7s n -- )
'[ dup peek-front _ = [ pop-front* ] [ drop ] if ] 4 napply ;
- next ( humble-iterator -- n )
dup dup { [ 2s>> ] [ 3s>> ] [ 5s>> ] [ 7s>> ] } cleave 4 ndup [ peek-front ] 4 napply min min min { [ ?pop ] [ swap enqueue ] [ count-digits ] [ ] } cleave ;
- upto-n-digits ( humble-iterator n -- seq )
1 + swap [ [ 2dup digits>> key? ] [ dup next , ] until ] { } make [ digits>> delete-at ] dip but-last-slice ;
- .first50 ( seq -- )
"First 50 humble numbers:" print 50 head [ pprint bl ] each nl ;
- .digit-breakdown ( humble-iterator -- )
"The digit counts of humble numbers:" print digits>> [ commas swap dup 1 = "" "s" ? "%9s have %2d digit%s\n" printf ] assoc-each ;
- humble-numbers ( -- )
[ <humble-iterator> dup 95 upto-n-digits [ .first50 nl ] [ drop .digit-breakdown nl ] [ "Total number of humble numbers found: " write length commas print ] tri ] time ;
MAIN: humble-numbers</lang>
- Output:
First 50 humble numbers: 1 2 3 4 5 6 7 8 9 10 12 14 15 16 18 20 21 24 25 27 28 30 32 35 36 40 42 45 48 49 50 54 56 60 63 64 70 72 75 80 81 84 90 96 98 100 105 108 112 120 The digit counts of humble numbers: 9 have 1 digit 36 have 2 digits 95 have 3 digits 197 have 4 digits 356 have 5 digits 579 have 6 digits 882 have 7 digits 1,272 have 8 digits 1,767 have 9 digits 2,381 have 10 digits 3,113 have 11 digits 3,984 have 12 digits 5,002 have 13 digits 6,187 have 14 digits 7,545 have 15 digits 9,081 have 16 digits 10,815 have 17 digits 12,759 have 18 digits 14,927 have 19 digits 17,323 have 20 digits 19,960 have 21 digits 22,853 have 22 digits 26,015 have 23 digits 29,458 have 24 digits 33,188 have 25 digits 37,222 have 26 digits 41,568 have 27 digits 46,245 have 28 digits 51,254 have 29 digits 56,618 have 30 digits 62,338 have 31 digits 68,437 have 32 digits 74,917 have 33 digits 81,793 have 34 digits 89,083 have 35 digits 96,786 have 36 digits 104,926 have 37 digits 113,511 have 38 digits 122,546 have 39 digits 132,054 have 40 digits 142,038 have 41 digits 152,515 have 42 digits 163,497 have 43 digits 174,986 have 44 digits 187,004 have 45 digits 199,565 have 46 digits 212,675 have 47 digits 226,346 have 48 digits 240,590 have 49 digits 255,415 have 50 digits 270,843 have 51 digits 286,880 have 52 digits 303,533 have 53 digits 320,821 have 54 digits 338,750 have 55 digits 357,343 have 56 digits 376,599 have 57 digits 396,533 have 58 digits 417,160 have 59 digits 438,492 have 60 digits 460,533 have 61 digits 483,307 have 62 digits 506,820 have 63 digits 531,076 have 64 digits 556,104 have 65 digits 581,902 have 66 digits 608,483 have 67 digits 635,864 have 68 digits 664,053 have 69 digits 693,065 have 70 digits 722,911 have 71 digits 753,593 have 72 digits 785,141 have 73 digits 817,554 have 74 digits 850,847 have 75 digits 885,037 have 76 digits 920,120 have 77 digits 956,120 have 78 digits 993,058 have 79 digits 1,030,928 have 80 digits 1,069,748 have 81 digits 1,109,528 have 82 digits 1,150,287 have 83 digits 1,192,035 have 84 digits 1,234,774 have 85 digits 1,278,527 have 86 digits 1,323,301 have 87 digits 1,369,106 have 88 digits 1,415,956 have 89 digits 1,463,862 have 90 digits 1,512,840 have 91 digits 1,562,897 have 92 digits 1,614,050 have 93 digits 1,666,302 have 94 digits 1,719,669 have 95 digits Total number of humble numbers found: 41,990,065 Running time: 335.1803624581294 seconds
Go
Not particularly fast and uses a lot of memory but easier to understand than the 'log' based methods for generating 7-smooth numbers. <lang go>package main
import (
"fmt" "math/big"
)
var (
one = new(big.Int).SetUint64(1) two = new(big.Int).SetUint64(2) three = new(big.Int).SetUint64(3) five = new(big.Int).SetUint64(5) seven = new(big.Int).SetUint64(7) ten = new(big.Int).SetUint64(10)
)
func min(a, b *big.Int) *big.Int {
if a.Cmp(b) < 0 { return a } return b
}
func humble(n int) []*big.Int {
h := make([]*big.Int, n) h[0] = new(big.Int).Set(one) next2, next3 := new(big.Int).Set(two), new(big.Int).Set(three) next5, next7 := new(big.Int).Set(five), new(big.Int).Set(seven) var i, j, k, l int for m := 1; m < len(h); m++ { h[m] = new(big.Int).Set(min(next2, min(next3, min(next5, next7)))) if h[m].Cmp(next2) == 0 { i++ next2.Mul(two, h[i]) } if h[m].Cmp(next3) == 0 { j++ next3.Mul(three, h[j]) } if h[m].Cmp(next5) == 0 { k++ next5.Mul(five, h[k]) } if h[m].Cmp(next7) == 0 { l++ next7.Mul(seven, h[l]) } } return h
}
func commatize(n int) string {
s := fmt.Sprintf("%d", n) le := len(s) for i := le - 3; i >= 1; i -= 3 { s = s[0:i] + "," + s[i:] } return s
}
func main() {
const n = 13 * 1e6 // calculate the first 13 million humble numbers, say h := humble(n) fmt.Println("The first 50 humble numbers are:") fmt.Println(h[0:50])
maxDigits := len(h[len(h)-1].String()) - 1 counts := make([]int, maxDigits+1) var maxUsed int digits := 1 pow10 := new(big.Int).Set(ten) for i := 0; i < len(h); i++ { for { if h[i].Cmp(pow10) >= 0 { pow10.Mul(pow10, ten) digits++ } else { break } } if digits > maxDigits { maxUsed = i break } counts[digits]++ } fmt.Printf("\nOf the first %s humble numbers:\n", commatize(maxUsed)) for i := 1; i <= maxDigits; i++ { s := "s" if i == 1 { s = "" } fmt.Printf("%9s have %2d digit%s\n", commatize(counts[i]), i, s) }
}</lang>
- Output:
The first 50 humble numbers are: [1 2 3 4 5 6 7 8 9 10 12 14 15 16 18 20 21 24 25 27 28 30 32 35 36 40 42 45 48 49 50 54 56 60 63 64 70 72 75 80 81 84 90 96 98 100 105 108 112 120] Of the first 12,591,874 humble numbers: 9 have 1 digit 36 have 2 digits 95 have 3 digits 197 have 4 digits 356 have 5 digits 579 have 6 digits 882 have 7 digits 1,272 have 8 digits 1,767 have 9 digits 2,381 have 10 digits 3,113 have 11 digits 3,984 have 12 digits 5,002 have 13 digits 6,187 have 14 digits 7,545 have 15 digits 9,081 have 16 digits 10,815 have 17 digits 12,759 have 18 digits 14,927 have 19 digits 17,323 have 20 digits 19,960 have 21 digits 22,853 have 22 digits 26,015 have 23 digits 29,458 have 24 digits 33,188 have 25 digits 37,222 have 26 digits 41,568 have 27 digits 46,245 have 28 digits 51,254 have 29 digits 56,618 have 30 digits 62,338 have 31 digits 68,437 have 32 digits 74,917 have 33 digits 81,793 have 34 digits 89,083 have 35 digits 96,786 have 36 digits 104,926 have 37 digits 113,511 have 38 digits 122,546 have 39 digits 132,054 have 40 digits 142,038 have 41 digits 152,515 have 42 digits 163,497 have 43 digits 174,986 have 44 digits 187,004 have 45 digits 199,565 have 46 digits 212,675 have 47 digits 226,346 have 48 digits 240,590 have 49 digits 255,415 have 50 digits 270,843 have 51 digits 286,880 have 52 digits 303,533 have 53 digits 320,821 have 54 digits 338,750 have 55 digits 357,343 have 56 digits 376,599 have 57 digits 396,533 have 58 digits 417,160 have 59 digits 438,492 have 60 digits 460,533 have 61 digits 483,307 have 62 digits 506,820 have 63 digits 531,076 have 64 digits 556,104 have 65 digits 581,902 have 66 digits 608,483 have 67 digits 635,864 have 68 digits 664,053 have 69 digits 693,065 have 70 digits
Haskell
<lang haskell>import Data.Set (deleteFindMin, fromList, union) import Control.Arrow ((&&&)) import Data.List (group) import Data.Bool (bool)
HUMBLE NUMBERS-----------------------
humbles :: [Integer] humbles =
let go sofar = x : go (union pruned $ fromList ((x *) <$> [2, 3, 5, 7])) where (x, pruned) = deleteFindMin sofar in go $ fromList [1]
-- humbles = filter (all (< 8) . primeFactors) [1 ..]
TEST----------------------------
main :: IO () main = do
putStrLn "First 50 Humble numbers:" mapM_ (putStrLn . concat) $ chunksOf 10 $ (justifyRight 4 ' ' . show) <$> take 50 humbles putStrLn "\nCount of humble numbers for each digit length 1-25:" mapM_ print $ take 25 $ (head &&& length) <$> group ((length . show) <$> humbles)
DISPLAY--------------------------
chunksOf :: Int -> [a] -> a chunksOf n xs =
foldr (\(x, i) a -> bool (take n (drop i xs) : a) a (rem i n > 0)) [] (zip xs [0 ..])
justifyRight :: Int -> a -> [a] -> [a] justifyRight n c = (drop . length) <*> (replicate n c ++)</lang>
- Output:
First 50 Humble numbers: 1 2 3 4 5 6 7 8 9 10 12 14 15 16 18 20 21 24 25 27 28 30 32 35 36 40 42 45 48 49 50 54 56 60 63 64 70 72 75 80 81 84 90 96 98 100 105 108 112 120 Count of humble numbers for each digit length 1-25: (1,9) (2,36) (3,95) (4,197) (5,356) (6,579) (7,882) (8,1272) (9,1767) (10,2381) (11,3113) (12,3984) (13,5002) (14,6187) (15,7545) (16,9081) (17,10815) (18,12759) (19,14927) (20,17323) (21,19960) (22,22853) (23,26015) (24,29458) (25,33188)
JavaScript
<lang javascript>(() => {
'use strict';
// -------------------HUMBLE NUMBERS-------------------
// humbles :: () -> [Int] function* humbles() { // A non-finite stream of Humble numbers. // OEIS A002473 const hs = new Set([1]); while (true) { let nxt = Math.min(...hs) yield nxt; hs.delete(nxt); [2, 3, 5, 7].forEach( x => hs.add(nxt * x) ); } };
// ------------------------TEST------------------------ // main :: IO () const main = () => { console.log('First 50 humble numbers:\n') chunksOf(10)(take(50)(humbles())).forEach( row => console.log( concat(row.map(compose(justifyRight(4)(' '), str))) ) ); console.log( '\nCounts of humble numbers of given digit lengths:' ); const counts = map(length)( group(takeWhileGen(x => 11 > x)( fmapGen(x => str(x).length)( humbles() ) )) ); console.log( fTable('\n')(str)(str)( i => counts[i - 1] )(enumFromTo(1)(10)) ); };
// -----------------GENERIC FUNCTIONS------------------
// chunksOf :: Int -> [a] -> a const chunksOf = n => xs => enumFromThenTo(0)(n)( xs.length - 1 ).reduce( (a, i) => a.concat([xs.slice(i, (n + i))]), [] );
// compose (<<<) :: (b -> c) -> (a -> b) -> a -> c const compose = (...fs) => x => fs.reduceRight((a, f) => f(a), x);
// concat :: a -> [a] // concat :: [String] -> String const concat = xs => 0 < xs.length ? (() => { const unit = 'string' !== typeof xs[0] ? ( [] ) : ; return unit.concat.apply(unit, xs); })() : [];
// enumFromThenTo :: Int -> Int -> Int -> [Int] const enumFromThenTo = x1 => x2 => y => { const d = x2 - x1; return Array.from({ length: Math.floor(y - x2) / d + 2 }, (_, i) => x1 + (d * i)); };
// enumFromTo :: Int -> Int -> [Int] const enumFromTo = m => n => Array.from({ length: 1 + n - m }, (_, i) => m + i);
// fTable :: String -> (a -> String) -> (b -> String) // -> (a -> b) -> [a] -> String const fTable = s => xShow => fxShow => f => xs => { // Heading -> x display function -> // fx display function -> // f -> values -> tabular string const ys = xs.map(xShow), w = Math.max(...ys.map(length)); return s + '\n' + zipWith( a => b => a.padStart(w, ' ') + ' -> ' + b )(ys)( xs.map(x => fxShow(f(x))) ).join('\n'); };
// fmapGen <$> :: (a -> b) -> Gen [a] -> Gen [b] const fmapGen = f => function*(gen) { let v = take(1)(gen); while (0 < v.length) { yield(f(v[0])) v = take(1)(gen) } };
// group :: [a] -> a const group = xs => { const go = xs => 0 < xs.length ? (() => { const h = xs[0], i = xs.findIndex(x => h !== x); return i !== -1 ? ( [xs.slice(0, i)].concat(go(xs.slice(i))) ) : [xs]; })() : []; return go(xs); };
// justifyRight :: Int -> Char -> String -> String const justifyRight = n => cFiller => s => n > s.length ? ( s.padStart(n, cFiller) ) : s;
// Returns Infinity over objects without finite length. // This enables zip and zipWith to choose the shorter // argument when one is non-finite, like cycle, repeat etc
// length :: [a] -> Int const length = xs => (Array.isArray(xs) || 'string' === typeof xs) ? ( xs.length ) : Infinity;
// map :: (a -> b) -> [a] -> [b] const map = f => xs => (Array.isArray(xs) ? ( xs ) : xs.split()).map(f);
// str :: a -> String const str = x => x.toString();
// take :: Int -> [a] -> [a] // take :: Int -> String -> String const take = n => xs => 'GeneratorFunction' !== xs.constructor.constructor.name ? ( xs.slice(0, n) ) : [].concat.apply([], Array.from({ length: n }, () => { const x = xs.next(); return x.done ? [] : [x.value]; }));
// takeWhileGen :: (a -> Bool) -> Gen [a] -> [a] const takeWhileGen = p => xs => { const ys = []; let nxt = xs.next(), v = nxt.value; while (!nxt.done && p(v)) { ys.push(v); nxt = xs.next(); v = nxt.value } return ys; };
// zipWith :: (a -> b -> c) -> [a] -> [b] -> [c] const zipWith = f => xs => ys => { const lng = Math.min(length(xs), length(ys)), as = take(lng)(xs), bs = take(lng)(ys); return Array.from({ length: lng }, (_, i) => f(as[i])( bs[i] )); };
// MAIN --- return main();
})();</lang>
- Output:
First 50 humble numbers: 1 2 3 4 5 6 7 8 9 10 12 14 15 16 18 20 21 24 25 27 28 30 32 35 36 40 42 45 48 49 50 54 56 60 63 64 70 72 75 80 81 84 90 96 98 100 105 108 112 120 Counts of humble numbers of given digit lengths: 1 -> 9 2 -> 36 3 -> 95 4 -> 197 5 -> 356 6 -> 579 7 -> 882 8 -> 1272 9 -> 1767 10 -> 2381
Julia
To spare heap memory, keeps only the last 2 million values found for use in the generation of further values. <lang julia> function counthumbledigits(maxdigits, returnsequencelength=50)
n, count, adjustindex, maxdiff = BigInt(1), 0, BigInt(0), 0 humble, savesequence = Vector{BigInt}([1]), Vector{BigInt}() base2, base3, base5, base7 = 1, 1, 1, 1 next2, next3, next5, next7 = BigInt(2), BigInt(3), BigInt(5), BigInt(7) digitcounts= Dict{Int, Int}(1 => 1) while n < BigInt(10)^(maxdigits+1) n = min(next2, next3, next5, next7) push!(humble, n) count += 1 if count == returnsequencelength savesequence = deepcopy(humble[1:returnsequencelength]) elseif count > 2000000 popfirst!(humble) adjustindex += 1 end placesbase10 = length(string(n)) if haskey(digitcounts, placesbase10) digitcounts[placesbase10] += 1 else digitcounts[placesbase10] = 1 end maxdiff = max(maxdiff, count - base2, count - base3, count - base5, count - base7) (next2 <= n) && (next2 = 2 * humble[(base2 += 1) - adjustindex]) (next3 <= n) && (next3 = 3 * humble[(base3 += 1) - adjustindex]) (next5 <= n) && (next5 = 5 * humble[(base5 += 1) - adjustindex]) (next7 <= n) && (next7 = 7 * humble[(base7 += 1) - adjustindex]) end savesequence, digitcounts, count, maxdiff
end
counthumbledigits(3)
@time first120, digitcounts, count, maxdiff = counthumbledigits(99)
println("\nTotal humble numbers counted: $count") println("Maximum depth between top of array and a multiplier: $maxdiff\n")
println("The first 50 humble numbers are: $first120\n\nDigit counts of humble numbers:") for ndigits in sort(collect(keys(digitcounts)))[1:end-1]
println(lpad(digitcounts[ndigits], 10), " have ", lpad(ndigits, 3), " digits.")
end
</lang>
- Output:
828.693164 seconds (3.61 G allocations: 64.351 GiB, 51.37% gc time) Total humble numbers counted: 51428827 Maximum depth between top of array and a multiplier: 1697189 The first 50 humble numbers are: BigInt[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 15, 16, 18, 20, 21, 24, 25, 27, 28, 30, 32, 35, 36, 40, 42, 45, 48, 49, 50, 54, 56, 60, 63, 64, 70, 72, 75, 80, 81, 84, 90, 96, 98, 100, 105, 108, 112, 120] Digit counts of humble numbers: 9 have 1 digits. 36 have 2 digits. 95 have 3 digits. 197 have 4 digits. 356 have 5 digits. 579 have 6 digits. 882 have 7 digits. 1272 have 8 digits. 1767 have 9 digits. 2381 have 10 digits. 3113 have 11 digits. 3984 have 12 digits. 5002 have 13 digits. 6187 have 14 digits. 7545 have 15 digits. 9081 have 16 digits. 10815 have 17 digits. 12759 have 18 digits. 14927 have 19 digits. 17323 have 20 digits. 19960 have 21 digits. 22853 have 22 digits. 26015 have 23 digits. 29458 have 24 digits. 33188 have 25 digits. 37222 have 26 digits. 41568 have 27 digits. 46245 have 28 digits. 51254 have 29 digits. 56618 have 30 digits. 62338 have 31 digits. 68437 have 32 digits. 74917 have 33 digits. 81793 have 34 digits. 89083 have 35 digits. 96786 have 36 digits. 104926 have 37 digits. 113511 have 38 digits. 122546 have 39 digits. 132054 have 40 digits. 142038 have 41 digits. 152515 have 42 digits. 163497 have 43 digits. 174986 have 44 digits. 187004 have 45 digits. 199565 have 46 digits. 212675 have 47 digits. 226346 have 48 digits. 240590 have 49 digits. 255415 have 50 digits. 270843 have 51 digits. 286880 have 52 digits. 303533 have 53 digits. 320821 have 54 digits. 338750 have 55 digits. 357343 have 56 digits. 376599 have 57 digits. 396533 have 58 digits. 417160 have 59 digits. 438492 have 60 digits. 460533 have 61 digits. 483307 have 62 digits. 506820 have 63 digits. 531076 have 64 digits. 556104 have 65 digits. 581902 have 66 digits. 608483 have 67 digits. 635864 have 68 digits. 664053 have 69 digits. 693065 have 70 digits. 722911 have 71 digits. 753593 have 72 digits. 785141 have 73 digits. 817554 have 74 digits. 850847 have 75 digits. 885037 have 76 digits. 920120 have 77 digits. 956120 have 78 digits. 993058 have 79 digits. 1030928 have 80 digits. 1069748 have 81 digits. 1109528 have 82 digits. 1150287 have 83 digits. 1192035 have 84 digits. 1234774 have 85 digits. 1278527 have 86 digits. 1323301 have 87 digits. 1369106 have 88 digits. 1415956 have 89 digits. 1463862 have 90 digits. 1512840 have 91 digits. 1562897 have 92 digits. 1614050 have 93 digits. 1666302 have 94 digits. 1719669 have 95 digits. 1774166 have 96 digits. 1829805 have 97 digits. 1886590 have 98 digits. 1944540 have 99 digits. 2003661 have 100 digits.
Kotlin
<lang scala>fun isHumble(i: Int): Boolean {
if (i <= 1) return true if (i % 2 == 0) return isHumble(i / 2) if (i % 3 == 0) return isHumble(i / 3) if (i % 5 == 0) return isHumble(i / 5) if (i % 7 == 0) return isHumble(i / 7) return false
}
fun main() {
val limit: Int = Short.MAX_VALUE.toInt() val humble = mutableMapOf<Int, Int>() var count = 0 var num = 1
while (count < limit) { if (isHumble(num)) { val str = num.toString() val len = str.length humble.merge(len, 1) { a, b -> a + b }
if (count < 50) print("$num ") count++ } num++ } println("\n")
println("Of the first $count humble numbers:") num = 1 while (num < humble.size - 1) { if (humble.containsKey(num)) { val c = humble[num] println("%5d have %2d digits".format(c, num)) num++ } else { break } }
}</lang>
- Output:
1 2 3 4 5 6 7 8 9 10 12 14 15 16 18 20 21 24 25 27 28 30 32 35 36 40 42 45 48 49 50 54 56 60 63 64 70 72 75 80 81 84 90 96 98 100 105 108 112 120 Of the first 32767 humble numbers: 9 have 1 digits 36 have 2 digits 95 have 3 digits 197 have 4 digits 356 have 5 digits 579 have 6 digits 882 have 7 digits 1272 have 8 digits 1767 have 9 digits
Pascal
modification of hamming-numbers http://rosettacode.org/wiki/Hamming_numbers#a_fast_alternative
>BR>Check for the first ocurence of 2^i/5^i -> 10^i
Using float80/extended and float64/double and single/float32 version, to get a possibility to check values.
Up to 877 digits I was able to compare, than float80 run out of memory (13.5 Gb )
float80 and float64 got same values up to 877.float64 is 2,3x faster than float80
float32 get wrong at 37 digits,->37 104925 instead of 104926
runtime: 2 x digits => ~ runtime 2^4
<lang pascal>
{$IFDEF FPC}
{$MODE DELPHI} {$OPTIMIZATION ON,ALL} {$CODEALIGN proc=32,loop=1} {$ALIGN 16}
{$ELSE}
{$APPTYPE CONSOLE}
{$ENDIF} uses
sysutils;
const
//PlInit(4); <= maxPrimFakCnt+1 maxPrimFakCnt = 3;//3,7,11 to keep data 8-Byte aligned minElemCnt = 10;
type
tPrimList = array of NativeUint; tnumber = extended; tpNumber= ^tnumber; tElem = record n : tnumber;//ln(prime[0]^Pots[0]*... dummy: array[0..5] of byte;//extend extended to 16 byte Pots: array[0..maxPrimFakCnt] of word; end; tpElem = ^tElem; tElems = array of tElem; tElemArr = array [0..0] of tElem; tpElemArr = ^tElemArr;
tpFaktorRec = ^tFaktorRec; tFaktorRec = record frElems : tElems; frInsElems: tElems; frAktIdx : NativeUint; frMaxIdx : NativeUint; frPotNo : NativeUint; frActPot : NativeUint; frNextFr : tpFaktorRec; frActNumb: tElem; frLnPrime: tnumber; end; tArrFR = array of tFaktorRec;
//LoE == List of Elements function LoEGetNextElement(pFR :tpFaktorRec):tElem;forward;
var
Pl : tPrimList; ActIndex : NativeUint; ArrInsert : tElems;
procedure PlInit(n: integer); const
cPl : array[0..11] of byte=(2,3,5,7,11,13,17,19,23,29,31,37);
var
i : integer;
Begin
IF n>High(cPl)+1 then n := High(cPl) else IF n < 0 then n := 1; IF maxPrimFakCnt+1 < n then Begin writeln(' Need to compile with bigger maxPrimFakCnt '); Halt(0); end; setlength(Pl,n); dec(n); For i := 0 to n do Pl[i] := cPl[i];
end;
procedure AusgabeElem(pElem: tElem;ShowPot:Boolean=false); var
i : integer;
Begin
with pElem do Begin IF n < 23 then write(round(exp(n)),' ') else write('ln ',n:13:7); IF ShowPot then Begin For i := 0 to maxPrimFakCnt do write(' ',PL[i]:2,'^',Pots[i]); writeln end; end;
end;
procedure LoECreate(const Pl: tPrimList;var FA:tArrFR); var
i : integer;
Begin
setlength(ArrInsert,100); setlength(FA,Length(PL)); For i := 0 to High(PL) do with FA[i] do Begin //automatic zeroing IF i < High(PL) then Begin setlength(frElems,minElemCnt); setlength(frInsElems,minElemCnt); frNextFr := @FA[i+1] end else Begin setlength(frElems,2); setlength(frInsElems,0); frNextFr := NIL; end; frPotNo := i; frLnPrime:= ln(PL[i]); frMaxIdx := 0; frAktIdx := 0; frActPot := 1; With frElems[0] do Begin n := frLnPrime; Pots[i]:= 1; end; frActNumb := frElems[0]; end; ActIndex := 0;
end;
procedure LoEFree(var FA:tArrFR);
var
i : integer;
Begin
For i := High(FA) downto Low(FA) do setlength(FA[i].frElems,0); setLength(FA,0);
end;
function LoEGetActElem(pFr:tpFaktorRec):tElem;inline; Begin
with pFr^ do result := frElems[frAktIdx];
end;
function LoEGetActLstNumber(pFr:tpFaktorRec):tpNumber;inline; Begin
with pFr^ do result := @frElems[frAktIdx].n;
end;
procedure LoEIncInsArr(var a:tElems); Begin
setlength(a,Length(a)*8 div 5);
end;
procedure LoEIncreaseElems(pFr:tpFaktorRec;minCnt:NativeUint); var
newLen: NativeUint;
Begin
with pFR^ do begin newLen := Length(frElems); minCnt := minCnt+frMaxIdx; repeat newLen := newLen*8 div 5 +1; until newLen > minCnt; setlength(frElems,newLen); end;
end;
procedure LoEInsertNext(pFr:tpFaktorRec;Limit:tnumber); var
pNum : tpNumber; pElems : tpElemArr; cnt,i,u : NativeInt;
begin
with pFr^ do Begin //collect numbers of heigher primes cnt := 0; pNum := LoEGetActLstNumber(frNextFr); while Limit > pNum^ do Begin frInsElems[cnt] := LoEGetNextElement(frNextFr); inc(cnt); IF cnt > High(frInsElems) then LoEIncInsArr(frInsElems); pNum := LoEGetActLstNumber(frNextFr); end;
if cnt = 0 then EXIT;
i := frMaxIdx; u := frMaxIdx+cnt+1;
IF u > High(frElems) then LoEIncreaseElems(pFr,cnt);
IF frPotNo = 0 then inc(ActIndex,u); //Merge pElems := @frElems[0]; dec(cnt); dec(u); frMaxIdx:= u; repeat IF pElems^[i].n < frInsElems[cnt].n then Begin pElems^[u] := frInsElems[cnt]; dec(cnt); end else Begin pElems^[u] := pElems^[i]; dec(i); end; dec(u); until (i<0) or (cnt<0); IF i < 0 then For u := cnt downto 0 do pElems^[u] := frInsElems[u]; end;
end;
procedure LoEAppendNext(pFr:tpFaktorRec;Limit:tnumber); var
pNum : tpNumber; pElems : tpElemArr; i : NativeInt;
begin
with pFr^ do Begin i := frMaxIdx+1; pElems := @frElems[0]; pNum := LoEGetActLstNumber(frNextFr); while Limit > pNum^ do Begin IF i > High(frElems) then Begin LoEIncreaseElems(pFr,10); pElems := @frElems[0]; end; pElems^[i] := LoEGetNextElement(frNextFr); inc(i); pNum := LoEGetActLstNumber(frNextFr); end; inc(ActIndex,i); frMaxIdx:= i-1; end;
end;
procedure LoENextList(pFr:tpFaktorRec); var
pElems : tpElemArr; j,PotNum : NativeInt; lnPrime : tnumber;
begin
with pFR^ do Begin //increase all Elements by factor pElems := @frElems[0]; LnPrime := frLnPrime; PotNum := frPotNo; for j := frMaxIdx Downto 0 do with pElems^[j] do Begin n := LnPrime+n; inc(Pots[PotNum]); end; //x^j -> x^(j+1) j := frActPot+1; with frActNumb do begin n:= j*LnPrime; Pots[PotNum]:= j; end; frActPot := j; //if something follows IF frNextFr <> NIL then LoEInsertNext(pFR,frActNumb.n); frAktIdx := 0; end;
end;
function LoEGetNextElementPointer(pFR :tpFaktorRec):tpElem; Begin
with pFr^ do Begin IF frMaxIdx < frAktIdx then LoENextList(pFr); result := @frElems[frAktIdx]; inc(frAktIdx); inc(ActIndex); end;
end;
function LoEGetNextElement(pFR :tpFaktorRec):tElem; Begin
with pFr^ do Begin result := frElems[frAktIdx]; inc(frAktIdx); IF frMaxIdx < frAktIdx then LoENextList(pFr); inc(ActIndex); end;
end;
function LoEGetNextNumber(pFR :tpFaktorRec):tNumber; Begin
with pFr^ do Begin result := frElems[frAktIdx].n; inc(frAktIdx); IF frMaxIdx < frAktIdx then LoENextList(pFr); inc(ActIndex); end;
end;
procedure LoEGetNumber(pFR :tpFaktorRec;no:NativeUint); Begin
dec(no); while ActIndex < no do LoENextList(pFR); with pFr^ do frAktIdx := (no-(ActIndex-frMaxIdx)-1);
end;
procedure first50; var
FA: tArrFR; i : integer;
Begin
LoECreate(Pl,FA); write(1,' '); For i := 1 to 49 do AusgabeElem(LoEGetNextElement(@FA[0])); writeln; LoEFree(FA);
end;
procedure GetDigitCounts(MaxDigit:Uint32); var
T1,T0 : TDateTime; FA: tArrFR; i,j,LastCnt : NativeUint;
Begin
T0 := now; inc(MaxDigit); LoECreate(Pl,FA); i := 1; j := 0; writeln('Digits count total count '); repeat LastCnt := j; repeat inc(j); with LoEGetNextElementPointer(@FA[0])^ do IF (Pots[2]= i) AND (Pots[0]= i) then break; until false; writeln(i:4,j-LastCnt:12,j:15,(now-T0)*86.6e3:10:3,' s'); LastCnt := j; inc(i); until i = MaxDigit; LoEFree(FA); T1 := now; writeln('Total number of humble numbers found: ',j); writeln('Running time: ',(T1-T0)*86.6e6:0:0,' ms');
end;
Begin
//check if PlInit(4); <= maxPrimFakCnt+1 PlInit(4);// 3 -> 2,3,5/ 4 -> 2,3,5,7 first50; GetDigitCounts(100);
End.</lang>
- Output:
1 2 3 4 5 6 7 8 9 10 12 14 15 16 18 20 21 24 25 27 28 30 32 35 36 40 42 45 48 49 50 54 56 60 63 64 70 72 75 80 81 84 90 96 98 100 105 108 112 120 Digits count total count 1 9 9 0.000 s 2 36 45 0.000 s 3 95 140 0.000 s 4 197 337 0.000 s 5 356 693 0.001 s 6 579 1272 0.001 s 7 882 2154 0.001 s 8 1272 3426 0.001 s 9 1767 5193 0.001 s 10 2381 7574 0.001 s 11 3113 10687 0.001 s 12 3984 14671 0.001 s 13 5002 19673 0.001 s 14 6187 25860 0.002 s 15 7545 33405 0.002 s 16 9081 42486 0.003 s 17 10815 53301 0.003 s 18 12759 66060 0.004 s 19 14927 80987 0.004 s 20 17323 98310 0.005 s 21 19960 118270 0.006 s 22 22853 141123 0.007 s 23 26015 167138 0.008 s 24 29458 196596 0.009 s 25 33188 229784 0.009 s 26 37222 267006 0.010 s 27 41568 308574 0.011 s 28 46245 354819 0.011 s 29 51254 406073 0.012 s 30 56618 462691 0.013 s 31 62338 525029 0.014 s 32 68437 593466 0.015 s 33 74917 668383 0.016 s 34 81793 750176 0.018 s 35 89083 839259 0.019 s 36 96786 936045 0.021 s 37 104926 1040971 0.022 s 38 113511 1154482 0.025 s 39 122546 1277028 0.027 s 40 132054 1409082 0.028 s 41 142038 1551120 0.031 s 42 152515 1703635 0.033 s 43 163497 1867132 0.036 s 44 174986 2042118 0.039 s 45 187004 2229122 0.042 s 46 199565 2428687 0.045 s 47 212675 2641362 0.050 s 48 226346 2867708 0.053 s 49 240590 3108298 0.056 s 50 255415 3363713 0.061 s 51 270843 3634556 0.065 s 52 286880 3921436 0.070 s 53 303533 4224969 0.076 s 54 320821 4545790 0.081 s 55 338750 4884540 0.087 s 56 357343 5241883 0.094 s 57 376599 5618482 0.100 s 58 396533 6015015 0.106 s 59 417160 6432175 0.113 s 60 438492 6870667 0.122 s 61 460533 7331200 0.130 s 62 483307 7814507 0.137 s 63 506820 8321327 0.148 s 64 531076 8852403 0.156 s 65 556104 9408507 0.165 s 66 581902 9990409 0.177 s 67 608483 10598892 0.186 s 68 635864 11234756 0.197 s 69 664053 11898809 0.210 s 70 693065 12591874 0.222 s 71 722911 13314785 0.235 s 72 753593 14068378 0.250 s 73 785141 14853519 0.262 s 74 817554 15671073 0.275 s 75 850847 16521920 0.292 s 76 885037 17406957 0.305 s 77 920120 18327077 0.320 s 78 956120 19283197 0.338 s 79 993058 20276255 0.354 s 80 1030928 21307183 0.370 s 81 1069748 22376931 0.391 s 82 1109528 23486459 0.409 s 83 1150287 24636746 0.428 s 84 1192035 25828781 0.451 s 85 1234774 27063555 0.470 s 86 1278527 28342082 0.490 s 87 1323301 29665383 0.516 s 88 1369106 31034489 0.538 s 89 1415956 32450445 0.559 s 90 1463862 33914307 0.582 s 91 1512840 35427147 0.612 s 92 1562897 36990044 0.636 s 93 1614050 38604094 0.662 s 94 1666302 40270396 0.694 s 95 1719669 41990065 0.721 s 96 1774166 43764231 0.748 s 97 1829805 45594036 0.785 s 98 1886590 47480626 0.815 s 99 1944540 49425166 0.845 s 100 2003661 51428827 0.884 s 101 2063972 53492799 0.916 s 102 2125486 55618285 0.948 s 103 2188204 57806489 0.991 s 104 2252146 60058635 1.026 s 105 2317319 62375954 1.062 s 106 2383733 64759687 1.110 s 107 2451413 67211100 1.147 s 108 2520360 69731460 1.186 s 109 2590584 72322044 1.237 s 110 2662102 74984146 1.278 s .. shortened 120 3450981 105831533 1.795 s 130 4382079 145340170 2.450 s 140 5467187 194997130 3.298 s 150 6718091 256407329 4.318 s 170 9764417 421496245 7.055 s 180 11583420 528974086 8.822 s 190 13615367 655803459 10.972 s 200 15872045 804178604 13.424 s 300 53391941 4039954757 66.882 s 400 126350163 12719142480 207.622 s 500 246533493 30980806733 503.269 s 600 425728730 64142692268 1039.928 s 700 675722681 118701223590 1920.325 s 800 1008302151 202331504969 3265.469 s .. 876 1323548095 290737888948 4690.230 s 877 1328082553 292065971501 4709.931 s
Perl
<lang perl>use strict; use warnings; use List::Util 'min';
- use bigint # works, but slow
use Math::GMPz; # this module gives roughly 16x speed-up
sub humble_gen {
my @s = ([1], [1], [1], [1]); my @m = (2, 3, 5, 7); @m = map { Math::GMPz->new($_) } @m; # comment out to NOT use Math::GMPz
return sub { my $n = min $s[0][0], $s[1][0], $s[2][0], $s[3][0]; for (0..3) { shift @{$s[$_]} if $s[$_][0] == $n; push @{$s[$_]}, $n * $m[$_] } return $n }
}
my $h = humble_gen; my $i = 0; my $upto = 50;
my $list; ++$i, $list .= $h->(). " " until $i == $upto; print "$list\n";
$h = humble_gen; # from the top... my $count = 0; my $digits = 1;
while ($digits <= $upto) {
++$count and next if $digits == length $h->(); printf "Digits: %2d - Count: %s\n", $digits++, $count; $count = 1;
}</lang>
- Output:
1 2 3 4 5 6 7 8 9 10 12 14 15 16 18 20 21 24 25 27 28 30 32 35 36 40 42 45 48 49 50 54 56 60 63 64 70 72 75 80 81 84 90 96 98 100 105 108 112 120 Digits: 1 - Count: 9 Digits: 2 - Count: 36 Digits: 3 - Count: 95 Digits: 4 - Count: 197 Digits: 5 - Count: 356 Digits: 6 - Count: 579 Digits: 7 - Count: 882 Digits: 8 - Count: 1272 Digits: 9 - Count: 1767 Digits: 10 - Count: 2381 Digits: 11 - Count: 3113 Digits: 12 - Count: 3984 Digits: 13 - Count: 5002 Digits: 14 - Count: 6187 Digits: 15 - Count: 7545 Digits: 16 - Count: 9081 Digits: 17 - Count: 10815 Digits: 18 - Count: 12759 Digits: 19 - Count: 14927 Digits: 20 - Count: 17323 Digits: 21 - Count: 19960 Digits: 22 - Count: 22853 Digits: 23 - Count: 26015 Digits: 24 - Count: 29458 Digits: 25 - Count: 33188 Digits: 26 - Count: 37222 Digits: 27 - Count: 41568 Digits: 28 - Count: 46245 Digits: 29 - Count: 51254 Digits: 30 - Count: 56618 Digits: 31 - Count: 62338 Digits: 32 - Count: 68437 Digits: 33 - Count: 74917 Digits: 34 - Count: 81793 Digits: 35 - Count: 89083 Digits: 36 - Count: 96786 Digits: 37 - Count: 104926 Digits: 38 - Count: 113511 Digits: 39 - Count: 122546 Digits: 40 - Count: 132054 Digits: 41 - Count: 142038 Digits: 42 - Count: 152515 Digits: 43 - Count: 163497 Digits: 44 - Count: 174986 Digits: 45 - Count: 187004 Digits: 46 - Count: 199565 Digits: 47 - Count: 212675 Digits: 48 - Count: 226346 Digits: 49 - Count: 240590 Digits: 50 - Count: 255415
Perl 6
<lang perl6>sub smooth-numbers (*@list) {
cache my \Smooth := gather { my %i = (flat @list) Z=> (Smooth.iterator for ^@list); my %n = (flat @list) Z=> 1 xx *;
loop { take my $n := %n{*}.min;
for @list -> \k { %n{k} = %i{k}.pull-one * k if %n{k} == $n; } } }
}
my $humble := smooth-numbers(2,3,5,7);
put $humble[^50]; say ;
my $upto = 50; my $digits = 1; my $count;
$humble.map: -> \h {
++$count and next if h.chars == $digits; printf "Digits: %2d - Count: %s\n", $digits++, $count; $count = 1; last if $digits > $upto;
}</lang>
- Output:
1 2 3 4 5 6 7 8 9 10 12 14 15 16 18 20 21 24 25 27 28 30 32 35 36 40 42 45 48 49 50 54 56 60 63 64 70 72 75 80 81 84 90 96 98 100 105 108 112 120 Digits: 1 - Count: 9 Digits: 2 - Count: 36 Digits: 3 - Count: 95 Digits: 4 - Count: 197 Digits: 5 - Count: 356 Digits: 6 - Count: 579 Digits: 7 - Count: 882 Digits: 8 - Count: 1272 Digits: 9 - Count: 1767 Digits: 10 - Count: 2381 Digits: 11 - Count: 3113 Digits: 12 - Count: 3984 Digits: 13 - Count: 5002 Digits: 14 - Count: 6187 Digits: 15 - Count: 7545 Digits: 16 - Count: 9081 Digits: 17 - Count: 10815 Digits: 18 - Count: 12759 Digits: 19 - Count: 14927 Digits: 20 - Count: 17323 Digits: 21 - Count: 19960 Digits: 22 - Count: 22853 Digits: 23 - Count: 26015 Digits: 24 - Count: 29458 Digits: 25 - Count: 33188 Digits: 26 - Count: 37222 Digits: 27 - Count: 41568 Digits: 28 - Count: 46245 Digits: 29 - Count: 51254 Digits: 30 - Count: 56618 Digits: 31 - Count: 62338 Digits: 32 - Count: 68437 Digits: 33 - Count: 74917 Digits: 34 - Count: 81793 Digits: 35 - Count: 89083 Digits: 36 - Count: 96786 Digits: 37 - Count: 104926 Digits: 38 - Count: 113511 Digits: 39 - Count: 122546 Digits: 40 - Count: 132054 Digits: 41 - Count: 142038 Digits: 42 - Count: 152515 Digits: 43 - Count: 163497 Digits: 44 - Count: 174986 Digits: 45 - Count: 187004 Digits: 46 - Count: 199565 Digits: 47 - Count: 212675 Digits: 48 - Count: 226346 Digits: 49 - Count: 240590 Digits: 50 - Count: 255415
Phix
I felt pretty good about the performance of this, until I ran the Go version - humbled indeed!
It will go all the way to 100 digits if you give it time (18 mins, on 64bit - 32bit runs out of memory after printing the 99th line)
I also tried a log version (similar to Hamming_numbers) but inaccuracies with floor(h[n][LOG]) crept in quite early, at just 10 digits.
<lang Phix>-- demo/rosetta/humble.exw
include mpfr.e
procedure humble(integer n, bool countdigits=false) -- if countdigits is false: show first n humble numbers, -- if countdigits is true: count them up to n digits.
sequence humble = {mpz_init(1)}, nexts = {2,3,5,7}, indices = repeat(1,4) for i=1 to 4 do nexts[i] = mpz_init(nexts[i]) end for integer digits = 1, count = 1, dead = 1, tc = 0 atom t0 = time() mpz p10 = mpz_init(10) while ((not countdigits) and length(humble)<n) or (countdigits and digits<=n) do mpz x = mpz_init_set(mpz_min(nexts)) humble = append(humble,x) if countdigits then if mpz_cmp(x,p10)>=0 then mpz_mul_si(p10,p10,10) integer d = min(indices) for k=dead to d-1 do humble[k] = mpz_free(humble[k]) end for dead = d string s = iff(digits=1?"":"s"), e = elapsed(time()-t0) tc += count
-- e &= sprintf(", %,d dead",{dead-1})
e &= sprintf(", total:%,d",{tc}) printf(1,"%,12d humble numbers have %d digit%s (%s)\n",{count,digits,s,e}) digits += 1 count = 1 else count += 1 end if end if for j=1 to 4 do if mpz_cmp(nexts[j],x)<=0 then indices[j] += 1 mpz_mul_si(nexts[j],humble[indices[j]],get_prime(j)) end if end for end while if not countdigits then for i=1 to length(humble) do humble[i] = shorten(mpz_get_str(humble[i]),ml:=10) end for printf(1,"First %d humble numbers: %s\n\n",{n,join(humble," ")}) end if
end procedure
humble(50) humble(42,true)</lang>
- Output:
First 50 humble numbers: 1 2 3 4 5 6 7 8 9 10 12 14 15 16 18 20 21 24 25 27 28 30 32 35 36 40 42 45 48 49 50 54 56 60 63 64 70 72 75 80 81 84 90 96 98 100 105 108 112 120 9 humble numbers have 1 digit (0s, total:9) 36 humble numbers have 2 digits (0s, total:45) 95 humble numbers have 3 digits (0s, total:140) 197 humble numbers have 4 digits (0s, total:337) 356 humble numbers have 5 digits (0s, total:693) 579 humble numbers have 6 digits (0.0s, total:1,272) 882 humble numbers have 7 digits (0.0s, total:2,154) 1,272 humble numbers have 8 digits (0.0s, total:3,426) 1,767 humble numbers have 9 digits (0.1s, total:5,193) 2,381 humble numbers have 10 digits (0.1s, total:7,574) 3,113 humble numbers have 11 digits (0.2s, total:10,687) 3,984 humble numbers have 12 digits (0.2s, total:14,671) 5,002 humble numbers have 13 digits (0.3s, total:19,673) 6,187 humble numbers have 14 digits (0.4s, total:25,860) 7,545 humble numbers have 15 digits (0.5s, total:33,405) 9,081 humble numbers have 16 digits (0.6s, total:42,486) 10,815 humble numbers have 17 digits (0.8s, total:53,301) 12,759 humble numbers have 18 digits (0.9s, total:66,060) 14,927 humble numbers have 19 digits (1.2s, total:80,987) 17,323 humble numbers have 20 digits (1.4s, total:98,310) 19,960 humble numbers have 21 digits (1.7s, total:118,270) 22,853 humble numbers have 22 digits (2.0s, total:141,123) 26,015 humble numbers have 23 digits (2.3s, total:167,138) 29,458 humble numbers have 24 digits (2.7s, total:196,596) 33,188 humble numbers have 25 digits (3.2s, total:229,784) 37,222 humble numbers have 26 digits (3.7s, total:267,006) 41,568 humble numbers have 27 digits (4.3s, total:308,574) 46,245 humble numbers have 28 digits (5.0s, total:354,819) 51,254 humble numbers have 29 digits (5.7s, total:406,073) 56,618 humble numbers have 30 digits (6.5s, total:462,691) 62,338 humble numbers have 31 digits (7.3s, total:525,029) 68,437 humble numbers have 32 digits (8.3s, total:593,466) 74,917 humble numbers have 33 digits (9.4s, total:668,383) 81,793 humble numbers have 34 digits (10.5s, total:750,176) 89,083 humble numbers have 35 digits (11.7s, total:839,259) 96,786 humble numbers have 36 digits (13.1s, total:936,045) 104,926 humble numbers have 37 digits (14.6s, total:1,040,971) 113,511 humble numbers have 38 digits (16.2s, total:1,154,482) 122,546 humble numbers have 39 digits (17.9s, total:1,277,028) 132,054 humble numbers have 40 digits (19.7s, total:1,409,082) 142,038 humble numbers have 41 digits (21.7s, total:1,551,120) 152,515 humble numbers have 42 digits (23.9s, total:1,703,635)
Python
<lang python>Humble numbers
from itertools import groupby, islice from functools import reduce
- humbles :: () -> [Int]
def humbles():
A non-finite stream of Humble numbers. OEIS A002473 hs = set([1]) while True: nxt = min(hs) yield nxt hs.remove(nxt) hs.update(nxt * x for x in [2, 3, 5, 7])
- TEST ----------------------------------------------------
- main :: IO ()
def main():
First 50, and counts with N digits
print('First 50 Humble numbers:\n') for row in chunksOf(10)( take(50)(humbles()) ): print(' '.join(map( lambda x: str(x).rjust(3), row )))
print('\nCounts of Humble numbers with n digits:\n') for tpl in take(10)( (k, len(list(g))) for k, g in groupby(len(str(x)) for x in humbles()) ): print(tpl)
- GENERIC -------------------------------------------------
- chunksOf :: Int -> [a] -> a
def chunksOf(n):
A series of lists of length n, subdividing the contents of xs. Where the length of xs is not evenly divible, the final list will be shorter than n. return lambda xs: reduce( lambda a, i: a + [xs[i:n + i]], range(0, len(xs), n), [] ) if 0 < n else []
- take :: Int -> [a] -> [a]
- take :: Int -> String -> String
def take(n):
The prefix of xs of length n, or xs itself if n > length xs. return lambda xs: ( list(islice(xs, n)) )
- MAIN ---
if __name__ == '__main__':
main()</lang>
- Output:
First 50 Humble numbers: 1 2 3 4 5 6 7 8 9 10 12 14 15 16 18 20 21 24 25 27 28 30 32 35 36 40 42 45 48 49 50 54 56 60 63 64 70 72 75 80 81 84 90 96 98 100 105 108 112 120 Counts of Humble numbers with n digits: (1, 9) (2, 36) (3, 95) (4, 197) (5, 356) (6, 579) (7, 882) (8, 1272) (9, 1767) (10, 2381)
Racket
<lang racket>#lang racket
(define (gen-humble-numbers N (kons #f) (k0 (void)))
(define rv (make-vector N 1))
(define (loop n 2-idx 3-idx 5-idx 7-idx next-2 next-3 next-5 next-7 k) (if (= n N) rv (let ((mn (min next-2 next-3 next-5 next-7))) (vector-set! rv n mn) (define (add-1-if-min n x) (if (= mn n) (add1 x) x)) (define (*vr.i-if-min n m i) (if (= mn n) (* m (vector-ref rv i)) n)) (let* ((2-idx (add-1-if-min next-2 2-idx)) (next-2 (*vr.i-if-min next-2 2 2-idx)) (3-idx (add-1-if-min next-3 3-idx)) (next-3 (*vr.i-if-min next-3 3 3-idx)) (5-idx (add-1-if-min next-5 5-idx)) (next-5 (*vr.i-if-min next-5 5 5-idx)) (7-idx (add-1-if-min next-7 7-idx)) (next-7 (*vr.i-if-min next-7 7 7-idx)) (k (and kons (kons mn k)))) (loop (add1 n) 2-idx 3-idx 5-idx 7-idx next-2 next-3 next-5 next-7 k))))) (loop 1 0 0 0 0 2 3 5 7 (and kons (kons 1 k0))))
(define ((digit-tracker breaker) h last-ten.count)
(let ((last-ten (car last-ten.count))) (if (< h last-ten) (cons last-ten (add1 (cdr last-ten.count))) (begin (printf "~a humble numbers with ~a digits~%" (cdr last-ten.count) (order-of-magnitude last-ten)) (cons (breaker (* 10 last-ten)) 1)))))
(define (Humble-numbers)
(displayln (gen-humble-numbers 50)) (time (let/ec break (void (gen-humble-numbers 100000000 (digit-tracker (λ (o) (if (> (order-of-magnitude o) 100) (break) o))) '(10 . 0))))))
(module+ main
(Humble-numbers))
</lang>
- Output:
output has been elided manually, to avoid repetition with the numbers you've already seen elsewhere:
#(1 2 3 4 5 6 7 8 9 10 12 14 15 16 18 20 21 24 25 27 28 30 32 35 36 40 42 45 48 49 50 54 56 60 63 64 70 72 75 80 81 84 90 96 98 100 105 108 112 120) 9 humble numbers with 1 digits 36 humble numbers with 2 digits 95 humble numbers with 3 digits 197 humble numbers with 4 digits 356 humble numbers with 5 digits 579 humble numbers with 6 digits 882 humble numbers with 7 digits 1272 humble numbers with 8 digits 1767 humble numbers with 9 digits 2381 humble numbers with 10 digits ... 17323 humble numbers with 20 digits ... 56618 humble numbers with 30 digits ... 132054 humble numbers with 40 digits ... 255415 humble numbers with 50 digits ... 438492 humble numbers with 60 digits ... 693065 humble numbers with 70 digits ... 1030928 humble numbers with 80 digits ... 1463862 humble numbers with 90 digits ... 2003661 humble numbers with 100 digits cpu time: 234970 real time: 235489 gc time: 189187
REXX
<lang rexx>/*REXX program computes and displays humble numbers, also will display counts of sizes.*/ parse arg n m . /*obtain optional arguments from the CL*/ if n== | n=="," then n= 50 /*Not specified? Then use the default.*/ if m== | m=="," then m= 60 /* " " " " " " */ numeric digits 1 + max(20, m) /*be able to handle some big numbers. */ $.= 0 /*a count array for X digit humble #s*/ call humble n; list= /*call HUMBLE sub; initialize the list.*/
do j=1 for n; list= list @.j /*append a humble number to the list.*/ end /*j*/
if list\= then do; say "A list of the first " n ' humble numbers are:'
say strip(list) /*elide the leading blank in the list. */ end
say call humble -m /*invoke subroutine for counting nums. */ if $.1==0 then exit /*if no counts, then we're all finished*/ total= 0 /*initialize count of humble numbers. */ $.1= $.1 + 1 /*adjust count for absent 1st humble #.*/ say ' The digit counts of humble numbers:' say ' ═════════════════════════════════════════'
do c=1 while $.c>0; s= left('s', length($.c)>1) /*count needs pluralization?*/ say right( commas($.c), 30) ' have ' right(c, 2) " digit"s total= total + $.c /* ◄─────────────────────────────────┐ */ end /*k*/ /*bump humble number count (so far)──┘ */
/*REXX program computes and displays humble numbers, also will display a count of sizes.*/ exit /*stick a fork in it, we're all done. */ /*──────────────────────────────────────────────────────────────────────────────────────*/ commas: procedure; arg _; do i=length(_)-3 to 1 by -3; _=insert(',', _, i); end; return _ /*──────────────────────────────────────────────────────────────────────────────────────*/ humble: procedure expose @. $.; parse arg x; if x==0 then return
y= abs(x); a= y; noCount= x>0; if x<0 then y= 999999999 #2= 1; #3= 1; #5= 1; #7= 1 /*define the initial humble constants. */ $.= 0; @.= 0; @.1= 1 /*initialize counts and humble numbers.*/ do h=2 for y-1 @.h= min(2*@.#2,3*@.#3,5*@.#5,7*@.#7) /*pick the minimum of 4 humble numbers.*/ m= @.h /*M: " " " " " " */ if 2*@.#2 == m then #2 = #2 + 1 /*Is number already defined? Use next #*/ if 3*@.#3 == m then #3 = #3 + 1 /* " " " " " " "*/ if 5*@.#5 == m then #5 = #5 + 1 /* " " " " " " "*/ if 7*@.#7 == m then #7 = #7 + 1 /* " " " " " " "*/ if noCount then iterate /*Not counting digits? Then iterate. */ L= length(m); if L>a then leave /*Are we done with counting? Then quit*/ $.L= $.L + 1 /*bump the digit count for this number.*/ end /*h*/ /*the humble numbers are in the @ array*/ return /* " count results " " " $ " */</lang>
- output when using the default inputs:
A list of the first 50 humble numbers are: 1 2 3 4 5 6 7 8 9 10 12 14 15 16 18 20 21 24 25 27 28 30 32 35 36 40 42 45 48 49 50 54 56 60 63 64 70 72 75 80 81 84 90 96 98 100 105 108 112 120 The digit counts of humble numbers: ═════════════════════════════════════════ 9 have 1 digit 36 have 2 digits 95 have 3 digits 197 have 4 digits 356 have 5 digits 579 have 6 digits 882 have 7 digits 1,272 have 8 digits 1,767 have 9 digits 2,381 have 10 digits 3,113 have 11 digits 3,984 have 12 digits 5,002 have 13 digits 6,187 have 14 digits 7,545 have 15 digits 9,081 have 16 digits 10,815 have 17 digits 12,759 have 18 digits 14,927 have 19 digits 17,323 have 20 digits 19,960 have 21 digits 22,853 have 22 digits 26,015 have 23 digits 29,458 have 24 digits 33,188 have 25 digits 37,222 have 26 digits 41,568 have 27 digits 46,245 have 28 digits 51,254 have 29 digits 56,618 have 30 digits 62,338 have 31 digits 68,437 have 32 digits 74,917 have 33 digits 81,793 have 34 digits 89,083 have 35 digits 96,786 have 36 digits 104,926 have 37 digits 113,511 have 38 digits 122,546 have 39 digits 132,054 have 40 digits 142,038 have 41 digits 152,515 have 42 digits 163,497 have 43 digits 174,986 have 44 digits 187,004 have 45 digits 199,565 have 46 digits 212,675 have 47 digits 226,346 have 48 digits 240,590 have 49 digits 255,415 have 50 digits 270,843 have 51 digits 286,880 have 52 digits 303,533 have 53 digits 320,821 have 54 digits 338,750 have 55 digits 357,343 have 56 digits 376,599 have 57 digits 396,533 have 58 digits 417,160 have 59 digits 438,492 have 60 digits total number of humble numbers found: 6,870,667
Sidef
<lang ruby>func smooth_generator(primes) {
var s = primes.len.of { [1] }
{ var n = s.map { .first }.min { |i| s[i].shift if (s[i][0] == n) s[i] << (n * primes[i]) } * primes.len n }
}
with (smooth_generator([2,3,5,7])) {|g|
say 50.of { g.run }.join(' ')
}
say "\nThe digit counts of humble numbers" say '═'*35
with (smooth_generator([2,3,5,7])) {|g|
for (var(d=1,c=0); d <= 20; ++c) { var n = g.run n.len > d || next say "#{'%10s'%c.commify} have #{'%2d'%d} digit#{[:s,][d==1]}" (c, d) = (0, n.len) }
}</lang>
- Output:
1 2 3 4 5 6 7 8 9 10 12 14 15 16 18 20 21 24 25 27 28 30 32 35 36 40 42 45 48 49 50 54 56 60 63 64 70 72 75 80 81 84 90 96 98 100 105 108 112 120 The digit counts of humble numbers ═══════════════════════════════════ 9 have 1 digit 36 have 2 digits 95 have 3 digits 197 have 4 digits 356 have 5 digits 579 have 6 digits 882 have 7 digits 1,272 have 8 digits 1,767 have 9 digits 2,381 have 10 digits 3,113 have 11 digits 3,984 have 12 digits 5,002 have 13 digits 6,187 have 14 digits 7,545 have 15 digits 9,081 have 16 digits 10,815 have 17 digits 12,759 have 18 digits 14,927 have 19 digits 17,323 have 20 digits
zkl
GNU Multiple Precision Arithmetic Library
<lang zkl>var [const] BI=Import("zklBigNum"); // libGMP var one = BI(1), two = BI(2), three = BI(3),
five = BI(5), seven = BI(7);
fcn humble(n){ // --> List of BigInt Humble numbers
h:=List.createLong(n); h.append(one); next2,next3 := two.copy(), three.copy(); next5,next7 := five.copy(), seven.copy(); reg i=0,j=0,k=0,l=0; do(n-1){ h.append( hm:=BI(next2.min(next3.min(next5.min(next7)))) ); if(hm==next2) next2.set(two) .mul(h[i+=1]); if(hm==next3) next3.set(three).mul(h[j+=1]); if(hm==next5) next5.set(five) .mul(h[k+=1]); if(hm==next7) next7.set(seven).mul(h[l+=1]); } h
}</lang> <lang zkl>fcn __main__{
const N = 5 * 1e6; // calculate the first 1 million humble numbers, say h:=humble(N); println("The first 50 humble numbers are:\n ",h[0,50].concat(" ")); counts:=Dictionary(); // tally the number of digits in each number h.apply2('wrap(n){ counts.incV(n.numDigits) });
println("\nOf the first %,d humble numbers:".fmt(h.len())); println("Digits Count"); foreach n in (counts.keys.apply("toInt").sort()){ println("%2d %,9d".fmt(n,counts[n], n)); }
}</lang>
- Output:
The first 50 humble numbers are: 1 2 3 4 5 6 7 8 9 10 12 14 15 16 18 20 21 24 25 27 28 30 32 35 36 40 42 45 48 49 50 54 56 60 63 64 70 72 75 80 81 84 90 96 98 100 105 108 112 120 Of the first 5,000,000 humble numbers: Digits Count 1 9 2 36 3 95 4 197 5 356 6 579 7 882 8 1,272 9 1,767 10 2,381 11 3,113 12 3,984 13 5,002 14 6,187 15 7,545 16 9,081 17 10,815 18 12,759 19 14,927 20 17,323 21 19,960 22 22,853 23 26,015 24 29,458 25 33,188 26 37,222 27 41,568 28 46,245 29 51,254 30 56,618 31 62,338 32 68,437 33 74,917 34 81,793 35 89,083 36 96,786 37 104,926 38 113,511 39 122,546 40 132,054 41 142,038 42 152,515 43 163,497 44 174,986 45 187,004 46 199,565 47 212,675 48 226,346 49 240,590 50 255,415 51 270,843 52 286,880 53 303,533 54 320,821 55 338,750 56 115,460