242 lines
4.5 KiB
Plaintext
242 lines
4.5 KiB
Plaintext
program AmicPair;
|
|
{find amicable pairs in a limited region 2..MAX
|
|
beware that >both< numbers must be smaller than MAX
|
|
there are 455 amicable pairs up to 524*1000*1000
|
|
correct up to
|
|
#437 460122410
|
|
}
|
|
//optimized for freepascal 2.6.4 32-Bit
|
|
{$IFDEF FPC}
|
|
{$MODE DELPHI}
|
|
{$OPTIMIZATION ON,peephole,cse,asmcse,regvar}
|
|
{$CODEALIGN loop=1,proc=8}
|
|
{$ELSE}
|
|
{$APPTYPE CONSOLE}
|
|
{$ENDIF}
|
|
|
|
uses
|
|
sysutils;
|
|
|
|
type
|
|
tValue = LongWord;
|
|
tpValue = ^tValue;
|
|
tDivSum = array[0..0] of tValue;// evil, but dynamic arrays are slower
|
|
tpDivSum = ^tDivSum;
|
|
tPower = array[0..31] of tValue;
|
|
tIndex = record
|
|
idxI,
|
|
idxS : tValue;
|
|
end;
|
|
var
|
|
power,
|
|
PowerFac : tPower;
|
|
ds : array of tValue;
|
|
Indices : array[0..511] of tIndex;
|
|
DivSumField : tpDivSum;
|
|
MAX : tValue;
|
|
|
|
procedure Init;
|
|
var
|
|
i : LongInt;
|
|
begin
|
|
DivSumField[0]:= 0;
|
|
For i := 1 to MAX do
|
|
DivSumField[i]:= 1;
|
|
end;
|
|
|
|
procedure ProperDivs(n: tValue);
|
|
//Only for output, normally a factorication would do
|
|
var
|
|
su,so : string;
|
|
i,q : tValue;
|
|
begin
|
|
su:= '1';
|
|
so:= '';
|
|
i := 2;
|
|
while i*i <= n do
|
|
begin
|
|
q := n div i;
|
|
IF q*i -n = 0 then
|
|
begin
|
|
su:= su+','+IntToStr(i);
|
|
IF q <> i then
|
|
so:= ','+IntToStr(q)+so;
|
|
end;
|
|
inc(i);
|
|
end;
|
|
writeln(' [',su+so,']');
|
|
end;
|
|
|
|
procedure AmPairOutput(cnt:tValue);
|
|
var
|
|
i : tValue;
|
|
r : double;
|
|
begin
|
|
r := 1.0;
|
|
For i := 0 to cnt-1 do
|
|
with Indices[i] do
|
|
begin
|
|
writeln(i+1:4,IdxI:12,IDxS:12,' ratio ',IdxS/IDxI:10:7);
|
|
if r < IdxS/IDxI then
|
|
r := IdxS/IDxI;
|
|
IF cnt < 20 then
|
|
begin
|
|
ProperDivs(IdxI);
|
|
ProperDivs(IdxS);
|
|
end;
|
|
end;
|
|
writeln(' max ratio ',r:10:4);
|
|
end;
|
|
|
|
function Check:tValue;
|
|
var
|
|
i,s,n : tValue;
|
|
begin
|
|
n := 0;
|
|
For i := 1 to MAX do
|
|
begin
|
|
//s = sum of proper divs (I) == sum of divs (I) - I
|
|
s := DivSumField^[i];
|
|
IF (s <=MAX) AND (s>i) AND (DivSumField^[s]= i)then
|
|
begin
|
|
With indices[n] do
|
|
begin
|
|
idxI := i;
|
|
idxS := s;
|
|
end;
|
|
inc(n);
|
|
end;
|
|
end;
|
|
result := n;
|
|
end;
|
|
|
|
Procedure CalcPotfactor(prim:tValue);
|
|
//PowerFac[k] = (prim^(k+1)-1)/(prim-1) == Sum (i=0..k) prim^i
|
|
var
|
|
k: tValue;
|
|
Pot, //== prim^k
|
|
PFac : Int64;
|
|
begin
|
|
Pot := prim;
|
|
PFac := 1;
|
|
For k := 0 to High(PowerFac) do
|
|
begin
|
|
PFac := PFac+Pot;
|
|
IF (POT > MAX) then
|
|
BREAK;
|
|
PowerFac[k] := PFac;
|
|
Pot := Pot*prim;
|
|
end;
|
|
end;
|
|
|
|
procedure InitPW(prim:tValue);
|
|
begin
|
|
fillchar(power,SizeOf(power),#0);
|
|
CalcPotfactor(prim);
|
|
end;
|
|
|
|
function NextPotCnt(p: tValue):tValue;
|
|
//return the first power <> 0
|
|
//power == n to base prim
|
|
var
|
|
i : tValue;
|
|
begin
|
|
result := 0;
|
|
repeat
|
|
i := power[result];
|
|
Inc(i);
|
|
IF i < p then
|
|
BREAK
|
|
else
|
|
begin
|
|
i := 0;
|
|
power[result] := 0;
|
|
inc(result);
|
|
end;
|
|
until false;
|
|
power[result] := i;
|
|
end;
|
|
|
|
procedure Sieve(prim: tValue);
|
|
var
|
|
actNumber,idx : tValue;
|
|
begin
|
|
//sieve with "small" primes
|
|
while prim*prim <= MAX do
|
|
begin
|
|
InitPW(prim);
|
|
Begin
|
|
//actNumber = actual number = n*prim
|
|
actNumber := prim;
|
|
idx := prim;
|
|
while actNumber <= MAX do
|
|
begin
|
|
dec(idx);
|
|
IF idx > 0 then
|
|
DivSumField^[actNumber] *= PowerFac[0]
|
|
else
|
|
Begin
|
|
DivSumField^[actNumber] *= PowerFac[NextPotCnt(prim)+1];
|
|
idx := Prim;
|
|
end;
|
|
inc(actNumber,prim);
|
|
end;
|
|
end;
|
|
//next prime
|
|
repeat
|
|
inc(prim);
|
|
until DivSumField^[prim]= 1;//(DivSumField[prim] = 1);
|
|
end;
|
|
|
|
//sieve with "big" primes, only one factor is possible
|
|
while 2*prim <= MAX do
|
|
begin
|
|
InitPW(prim);
|
|
Begin
|
|
actNumber := prim;
|
|
idx := PowerFac[0];
|
|
while actNumber <= MAX do
|
|
begin
|
|
DivSumField^[actNumber] *= idx;
|
|
inc(actNumber,prim);
|
|
end;
|
|
end;
|
|
repeat
|
|
inc(prim);
|
|
until DivSumField^[prim]= 1;
|
|
end;
|
|
|
|
For idx := 2 to MAX do
|
|
dec(DivSumField^[idx],idx);
|
|
end;
|
|
|
|
var
|
|
T2,T1,T0: TDatetime;
|
|
APcnt: tValue;
|
|
i: NativeInt;
|
|
begin
|
|
MAX := 20000;
|
|
IF ParamCount > 0 then
|
|
MAX := StrToInt(ParamStr(1));
|
|
setlength(ds,MAX);
|
|
DivSumField := @ds[0];
|
|
T0:= time;
|
|
For i := 1 to 1 do
|
|
Begin
|
|
Init;
|
|
Sieve(2);
|
|
end;
|
|
T1:= time;
|
|
|
|
APCnt := Check;
|
|
T2:= time;
|
|
AmPairOutput(APCnt);
|
|
writeln(APCnt,' amicable pairs til ',MAX);
|
|
writeln('Time to calc sum of divs ',FormatDateTime('HH:NN:SS.ZZZ' ,T1-T0));
|
|
writeln('Time to find amicable pairs ',FormatDateTime('HH:NN:SS.ZZZ' ,T2-T1));
|
|
setlength(ds,0);
|
|
{$IFNDEF UNIX}
|
|
readln;
|
|
{$ENDIF}
|
|
end.
|