Anonymous user
Zumkeller numbers: Difference between revisions
→{{header|Pascal}}: improved sieve for prime decompostion runtime for 1e9 down from 474 s to 170 s tested til 1e11
m (→{{header|Pascal}}: inserted TIO.RUN for counting 1..10,000,000) |
(→{{header|Pascal}}: improved sieve for prime decompostion runtime for 1e9 down from 474 s to 170 s tested til 1e11) |
||
Line 2,755:
1145529 1162161 1198197 1224531 1270269 1307691 1324323 1378377</pre>
=={{header|Pascal}}==
Using sieve for primedecomposition<BR>
Now using the trick, that one partition sum must include n and improved recursive search.<BR>
Limit is ~1.2e11
<lang pascal>program zumkeller;
//https://oeis.org/A083206/a083206.txt
{$IFDEF FPC}
{$MODE DELPHI} {$OPTIMIZATION ON,ALL} {$COPERATORS ON}
// {$O+,I+}
{$ELSE}
{$APPTYPE CONSOLE}
Line 2,774 ⟶ 2,772:
//######################################################################
//prime decomposition
const
//HCN(86) > 1.2E11 = 128,501,493,120 count of divs = 4096 7 3 1 1 1 1 1 1 1
HCN_DivCnt = 4096;
//stop never ending recursion
RECCOUNTMAX = 100*1000*1000;
DELTAMAX = 1000*1000;
type
tItem =
tDivisors = array [0..
tpDivisor =
const
SizePrDeFe = 12697;//*72 <= 1 or 2 Mb ~ level 2 cache -32kB for DIVS
type
tdigits = packed
end;
//the first number with 11 different divisors =
// 2*3*5*7*11*13*17*19*23*29*31 = 2E11
tprimeFac = packed record
pfRemain : Uint64; //n div (p[0]^[pPot[0] *...) can handle primes <=821641^2 = 6.7e11
pfpotMax : array[0..9] of byte; //10 = 66
pfMaxIdx : Uint16; //68
pfDivCnt : Uint32; //72
end;
tPrimeDecompField = array[0..SizePrDeFe-1] of tprimeFac;
tPrimes = array[0..65535] of Uint32;
var
SmallPrimes:
//######################################################################
//prime decomposition
procedure InitSmallPrimes;
//only odd numbers
const
MAXLIMIT = (821641-1) shr 1;
var
pr : array[0..MAXLIMIT] of byte;
p,j,d,flipflop :NativeUInt;
Begin
SmallPrimes[0] := 2;
fillchar(pr[0],SizeOf(pr),#0);
p := 0;
repeat
repeat
j :=
if
j += d;
until j>MAXLIMIT;
until false;
SmallPrimes[1] := 3;
SmallPrimes[2] := 5;
j := 3;
d := 7;
flipflop := 3-1;
p := 3;
repeat
if pr[p] = 0 then
begin
SmallPrimes[j] := d;
inc(j);
d += 2*flipflop;
p+=flipflop;
flipflop := 3-flipflop;
until (p > MAXLIMIT) OR (j>High(SmallPrimes));
end;
function OutPots(const pD:tprimeFac;n:NativeInt):Ansistring;
var
s: String[31];
Begin
str(n,s);
result := s+' :';
with pd do
begin
str(pfDivCnt:3,s);
result += s+' : ';
For n := 0 to pfMaxIdx-1 do
Begin
str(pFpotPrim[n],s);
result += s;
if pfpotMax[n] >1 then
Begin
str(pfpotMax[n],s);
result += '^'+s;
end;
end;
If pfRemain >1 then
Begin
str(pfRemain,s);
result += '*'+s;
end;
str(pfSumOfDivs,s);
result += '_SoD_'+s+'<';
end;
end;
function CnvtoBASE(var dgt:tDigits;n:Uint64;base:NativeUint):NativeInt;
//n must be multiple of base
var
q,r: Uint64;
i : NativeInt;
Begin
with dgt do
Begin
fillchar(dgtDgts,SizeOf(dgtDgts),#0);
i := 0;
// dgtNum:= n;
n := n div base;
result := 0;
repeat
r := n;
q := n div base;
r -= q*base;
n := q;
dgtDgts[i] := r;
inc(i);
until (q = 0);
result := 0;
while (result<i) AND (dgtDgts[result] = 0) do
inc(result);
inc(result);
end;
end;
function IncByBaseInBase(var dgt:tDigits;base:NativeInt):NativeInt;
var
q :NativeInt;
Begin
with dgt do
Begin
q := dgtDgts[result]+1;
//
if q
begin
repeat
dgtDgts[result] := 0;
inc(result);
q := dgtDgts[result]+1;
until q <> base;
end;
result +=1;
end;
procedure SieveOneSieve(var pdf:tPrimeDecompField;n:nativeUInt);
var
dgt:tDigits;
i, j, k,pr,fac : NativeUInt;
begin
//init
for i := 0 to High(pdf) do
with pdf[i] do
Begin
pfSumOfDivs := 1;
pfRemain :=
end;
//first 2
i :=
repeat
begin
end;
i +=
until i
// i now index in SmallPrimes
i := 0;
repeat
//search next prime that is in bounds of sieve
repeat
if i >= High(SmallPrimes) then
pr :=
k :=
if (k = pr)
if k < SizePrDeFe
until
if i >= High(SmallPrimes) then
//no need to use higher
j := CnvtoBASE(dgt,n+k,pr);
repeat
Begin
pfDivCnt
fac
until j<=
end;
j := IncByBaseInBase(dgt,pr);
until k >= SizePrDeFe;
until false;
//correct sum of & count of divisors
for i := 0 to High(pdf) do
Begin
begin
pfDivCnt
end;
end;
end;
end;
//prime decomposition
//######################################################################
procedure Init_Check_rec(const pD:tprimeFac;var Divs,SumOfDivs:tDivisors);forward;
var
{$ALIGN 32}
PrimeDecompField:tPrimeDecompField;
{$ALIGN 32}
Divs :tDivisors;
SumOfDivs : tDivisors;
DivUsedIdx : tDivisors;
pDiv :tpDivisor;
T0: Int64;
count,rec_Cnt: NativeInt;
depth : Int32;
finished :Boolean;
procedure Check_rek_depth(SoD : Int64;i: NativeInt);
var
sum : Int64;
begin
if finished then
EXIT;
inc(rec_Cnt);
WHILE (i>0) AND (pDiv[i]>SoD) do
dec(i);
while i >= 0
Begin
DivUsedIdx[depth] := pDiv[i];
if sum
begin
finished :=
end;
if (i>= 0) AND (sum <=
if finished then
// DivUsedIdx[depth] := 0;
end;
procedure Out_One_Sol(const pd:tprimefac;n:NativeUInt;isZK : Boolean);
var
Begin
if n< 7 then
exit;
with pd do
begin
writeln(OutPots(pD,n));
if isZK then
Begin
Init_Check_rec(pD,Divs,SumOfDivs);
Check_rek_depth(pfSumOfDivs shr 1-n,pFDivCnt-1);
write(pfSumOfDivs shr 1:10,' = ');
sum := n;
while depth >= 0 do
Begin
end;
write(n,' = ',sum);
end
else
write(' no zumkeller ');
end;
end;
Line 3,100 ⟶ 3,117:
end;
procedure GetDivs(const pD:tprimeFac;var Divs,SumOfDivs:tDivisors);
var
pDivs : tpDivisor;
i,len,j,l,p,k: Int32;
Begin
i :=
pDivs := @Divs[0];
pDivs[0] := 1;
len := 1;
l := 1;
Begin
For i := 0 to pfMaxIdx-1 do
begin
//Multiply every divisor before with the new primefactors
//and append them to the list
k :=
p :=
pPot :=1;
repeat
Line 3,126 ⟶ 3,145:
end;
dec(k);
until k<=0;
len := l;
end;
p := pfRemain;
If p >1 then
begin
For j := 0 to len-1 do
Begin
end;
len := l;
end;
end;
//Sort. Insertsort much faster than QuickSort in this special case
InsertSort(pDivs,0,len-1);
pPot := 0;
For i := 0 to len-1 do
begin
SumOfDivs[i] := pPot;
end;
end;
procedure
begin
GetDivs(pD,Divs,SUmOfDivs);
finished := false;
depth := 0;
pDiv := @Divs[0];
end;
Line 3,350 ⟶ 3,182:
sum : Int64;
begin
if finished then
EXIT;
if rec_Cnt >RECCOUNTMAX then
begin
rec_Cnt := -1;
finished := true;
exit;
end;
inc(rec_Cnt);
WHILE (i>0) AND (pDiv[i]>SoD) do
dec(i);
while i >= 0 do
Begin
sum := SoD-pDiv[i];
if sum = 0 then
begin
finished := true;
EXIT;
end;
Line 3,369 ⟶ 3,208:
if finished then
EXIT;
end;
end;
function GetZumKeller(n:
var
SoD,sum : Int64;
Div_cnt,i,pracLmt: NativeInt;
begin
SoD:= pd.pfSumOfDivs;
//sum must be even and n not deficient
if Odd(SoD) or (SoD<2*n) THEN
Line 3,391 ⟶ 3,226:
If SoD < 2 then //0,1 is always true
Exit(true);
Div_cnt :=
if Not(odd(n)) then
Line 3,400 ⟶ 3,234:
//Now one needs to get the divisors
pracLmt:= 0;
Line 3,418 ⟶ 3,245:
Begin
pracLmt := i;
BREAK;
end;
Line 3,426 ⟶ 3,252:
Exit(true);
end;
//
if pracLmt = (Div_Cnt-1) shr 1 then
begin
i := SoD mod Divs[pracLmt+1];
with
begin
if pfRemain > 1 then
EXIT((pfRemain<=i) OR (i<=sum))
else
EXIT((pfpotPrim[pfMaxIdx-1]<=i)OR (i<=sum));
end;
end;
Begin
IF Div_cnt <=
Begin
Check_rek(SoD,Div_cnt-1);
IF rec_Cnt = -1 then
exit(true);
exit(finished);
end;
Line 3,449 ⟶ 3,278:
var
Max: NativeUInt;
procedure Init_Sieve(n:NativeUint);
//Init Sieve i,oFs are Global
begin
Ofs := (n DIV SizePrDeFe)*SizePrDeFe;
SieveOneSieve(PrimeDecompField,Ofs);
end;
procedure GetSmall(MaxIdx:Int32);
var
ZK: Array of Uint32;
idx: UInt32;
Begin
If MaxIdx<1 then
EXIT;
writeln('The first ',MaxIdx,' zumkeller numbers');
Init_Sieve(0);
setlength(ZK,MaxIdx);
idx := Low(ZK);
repeat
if
Begin
inc(n);
If i > High(PrimeDecompField) then
begin
dec(i,SizePrDeFe);
inc(ofs,SizePrDeFe);
SieveOneSieve(PrimeDecompField,Ofs);
end;
until idx >= MaxIdx;
For idx := 0 to MaxIdx-1 do
begin
if idx MOD 20 = 0 then
writeln;
write(ZK[idx]:4);
end;
setlength(ZK,0);
writeln;
writeln;
end;
procedure GetOdd(MaxIdx:Int32);
var
ZK: Array of Uint32;
idx: UInt32;
Begin
If MaxIdx<1 then
EXIT;
writeln('The first odd 40 zumkeller numbers');
n := 1;
Init_Sieve(n);
setlength(
idx := Low(ZK);
repeat
if
Begin
inc(n,2);
If i > High(PrimeDecompField) then
begin
dec(i,SizePrDeFe);
inc(ofs,SizePrDeFe);
SieveOneSieve(PrimeDecompField,Ofs);
end;
until idx >= MaxIdx;
For idx := 0 to MaxIdx-1 do
begin
if idx MOD (80 DIV 8) = 0 then
writeln;
write(ZK[idx]:8);
end;
setlength(ZK,0);
writeln;
writeln;
end;
procedure GetOddNot5(MaxIdx:Int32);
var
ZK: Array of Uint32;
idx: UInt32;
Begin
If MaxIdx<1 then
EXIT;
writeln('The first odd 40 zumkeller numbers not ending in 5');
setlength(ZK,MaxIdx);
idx := Low(ZK);
repeat
if
Begin
inc(n,2);
begin
inc(i,2);
inc(n,2);
end;
If i > High(PrimeDecompField) then
begin
dec(i,SizePrDeFe);
inc(ofs,SizePrDeFe);
SieveOneSieve(PrimeDecompField,Ofs);
end;
until idx >= MaxIdx;
For idx := 0 to MaxIdx-1 do
begin
if idx MOD (80 DIV 8) = 0 then
writeln;
write(ZK[idx]:8);
end;
setlength(ZK,0);
writeln;
writeln;
end;
BEGIN
InitSmallPrimes;
T0 := GetTickCount64
GetSmall(220);
GetOddNot5(40);
writeln;
Init_Sieve(n);
writeln('Start ',n,' at ',i);
T0 := GetTickCount64;
MAX := (n DIV DELTAMAX+1)*DELTAMAX;
count := 0;
repeat
writeln('Count of zumkeller numbers up to ',MAX:12);
repeat
if GetZumKeller(n,PrimeDecompField[i]) then
If i > High(PrimeDecompField) then
dec(i,SizePrDeFe);
SieveOneSieve(PrimeDecompField,Ofs);
end;
writeln(n-1:10,' tested
MAX += DELTAMAX;
writeln('runtime ',(GetTickCount64-T0)/1000:8:3,' s');
writeln;
writeln('Count of recursion 59,641,327 for 8,996,229,720');
n := 8996229720;
Init_Sieve(n);
T0 := GetTickCount64;
Out_One_Sol(PrimeDecompField[i],n,true);
writeln;
writeln('runtime ',(GetTickCount64-T0)/1000:8:3,' s');
END.
</lang>
{{out}}
<pre>
TIO.RUN
6 12 20 24 28 30 40 42 48 54 56 60 66 70 78 80 84 88 90 96
102 104 108 112 114 120 126 132 138 140 150 156 160 168 174 176 180 186 192 198
204 208 210 216 220 222 224 228 234 240 246 252 258 260 264 270 272 276 280 282
294 300 304 306 308 312 318 320 330 336 340 342 348 350 352 354 360 364 366 368
372 378 380 384 390 396 402 408 414 416 420 426 432 438 440 444 448 456 460 462
464 468 474 476 480 486 490 492 496 498 500 504 510 516 520 522 528 532 534 540
544 546 550 552 558 560 564 570 572 580 582 588 594 600 606 608 612 616 618 620
624 630 636 640 642 644 650 654 660 666 672 678 680 684 690 696 700 702 704 708
714 720 726 728 732 736 740 744 750 756 760 762 768 770 780 786 792 798 804 810
812 816 820 822 828 832 834 836 840 852 858 860 864 868 870 876 880 888 894 896
906 910 912 918 920 924 928 930 936 940 942 945 948 952 960 966 972 978 980 984
The first odd 40 zumkeller numbers
945 1575 2205 2835 3465 4095 4725 5355 5775 5985
6435 6615 6825 7245 7425 7875 8085 8415 8505 8925
9135 9555 9765 10395 11655 12285 12705 12915 13545 14175
14805 15015 15435 16065 16695 17325 17955 18585 19215 19305
The first odd 40 zumkeller numbers not ending in 5
81081 153153 171171 189189 207207 223839 243243 261261 279279 297297
351351 459459 513513 567567 621621 671517 729729 742203 783783 793611
812889 837837 891891 908523 960687 999999 1024947 1054053 1072071 1073709
1095633 1108107 1145529 1162161 1198197 1224531 1270269 1307691 1324323 1378377
Start 1 at 1
Count of zumkeller numbers up to 1000000
1000000 tested found 229026 ratio 0.2290258
Count of zumkeller numbers up to 2000000
2000000 tested found 457658 ratio 0.2288289
Count of zumkeller numbers up to 3000000
3000000 tested found 686048 ratio 0.2286826
Count of zumkeller numbers up to 4000000
4000000 tested found 914806 ratio 0.2287014
Count of zumkeller numbers up to 5000000
5000000 tested found 1143521 ratio 0.2287042
Count of zumkeller numbers up to 6000000
6000000 tested found 1372208 ratio 0.2287013
Count of zumkeller numbers up to 7000000
7000000 tested found 1600977 ratio 0.2287110
Count of zumkeller numbers up to 8000000
8000000 tested found 1829932 ratio 0.2287415
Count of zumkeller numbers up to 9000000
9000000 tested found 2058883 ratio 0.2287648
Count of zumkeller numbers up to 10000000
10000000 tested found 2287889 ratio 0.2287889
runtime 1.268 s
//zumkeller number with highest recursion count til 1e11
Count of recursion 59,641,327 for 8,996,229,720
8996229720 : 96 : 2^3*3^2*5*2237*11171_SoD_29253435120<
14626717560 = 36+45+60+72+90+120+180+360+201330+804312+805320+2010780+4021560+1124528715+4498114860+8996229720 = 14626717560
runtime 7.068 s // at home 9.5s
Real time: 8.689 s CPU share: 98.74 %
9900000000 tested found 2262797501 ratio 0.2285654 recursion 10.479
runtime 48.805 s
Count of zumkeller numbers up to 10000000000
rek_ -1 @ 9998443080 : 96 : 2^3*3^2*5*3041*9133_SoD_32509184760<
10000000000 tested found 2285655276 ratio 0.2285655 recursion 10.520
runtime 28.976 s
real 40m7,478s user 40m7,039s sys 0m0,057s
only 4 til 4,512,612,672
out_1e10.txt:104: rek_ -1 @ 584818848 : 72 : 2^5*3^2*1423*1427_SoD_1665413568<
out_1e10.txt:105: rek_ -1 @ 589754016 : 72 : 2^5*3^2*1429*1433_SoD_1679457780<
out_1e10.txt:174: rek_ -1 @ 1956249450 : 72 : 2*3^2*5^2*2083*2087_SoD_5260832928<
out_1e10.txt:291: rek_ -1 @ 4512612672 : 84 : 2^6*3^2*2797*2801_SoD_12943833396<
</pre>
|