RosettaCodeData/Task/Amicable-pairs/Pascal/amicable-pairs-2.pascal

233 lines
4.2 KiB
Text
Raw Permalink Normal View History

2015-02-20 09:02:09 -05:00
program AmicablePairs;
{$IFDEF FPC}
{$MODE DELPHI}
2015-11-18 06:14:39 +00:00
{$H+}
2015-02-20 09:02:09 -05:00
{$ELSE}
{$APPTYPE CONSOLE}
{$ENDIF}
uses
sysutils;
const
2015-11-18 06:14:39 +00:00
MAX = 20000;
//MAX = 20*1000*1000;
2015-02-20 09:02:09 -05:00
type
tValue = LongWord;
tpValue = ^tValue;
tPower = array[0..31] of tValue;
tIndex = record
idxI,
2015-11-18 06:14:39 +00:00
idxS : Uint64;
2015-02-20 09:02:09 -05:00
end;
2015-11-18 06:14:39 +00:00
2015-02-20 09:02:09 -05:00
var
Indices : array[0..511] of tIndex;
2015-11-18 06:14:39 +00:00
//primes up to 65536 enough until 2^32
primes : array[0..6542] of tValue;
procedure InitPrimes;
// sieve of erathosthenes without multiples of 2
type
tSieve = array[0..(65536-1) div 2] of char;
var
ESieve : ^tSieve;
idx,i,j,p : LongINt;
Begin
new(ESieve);
fillchar(ESieve^[0],SizeOF(tSieve),#1);
primes[0] := 2;
idx := 1;
//sieving
j := 1;
p := 2*j+1;
repeat
if Esieve^[j] = #1 then
begin
i := (2*j+2)*j;// i := (sqr(p) -1) div 2;
if i > High(tSieve) then
BREAK;
repeat
ESIeve^[i] := #0;
inc(i,p);
until i > High(tSieve);
end;
inc(j);
inc(p,2);
until j >High(tSieve);
//collecting
For i := 1 to High(tSieve) do
IF Esieve^[i] = #1 then
Begin
primes[idx] := 2*i+1;
inc(idx);
IF idx>High(primes) then
BREAK;
end;
dispose(Esieve);
end;
2015-02-20 09:02:09 -05:00
2015-11-18 06:14:39 +00:00
procedure Su_append(n,factor:tValue;var su:string);
2015-02-20 09:02:09 -05:00
var
2015-11-18 06:14:39 +00:00
q,p : tValue;
2015-02-20 09:02:09 -05:00
begin
2015-11-18 06:14:39 +00:00
p := 0;
repeat
q := n div factor;
IF q*factor<>n then
Break;
inc(p);
n := q;
until false;
IF p > 0 then
IF p= 1 then
su:= su+IntToStr(factor)+'*'
else
su:= su+IntToStr(factor)+'^'+IntToStr(p)+'*';
2015-02-20 09:02:09 -05:00
end;
2015-11-18 06:14:39 +00:00
procedure ProperDivs(n: Uint64);
//output of prime factorization
2015-02-20 09:02:09 -05:00
var
2015-11-18 06:14:39 +00:00
su : string;
primNo : tValue;
p:tValue;
2015-02-20 09:02:09 -05:00
begin
2015-11-18 06:14:39 +00:00
str(n:8,su);
su:= su +' [';
primNo := 0;
p := primes[0];
repeat
Su_Append(n,p,su);
inc(primNo);
p := primes[primNo];
until (p=0) OR (p*p >= n);
p := n;
Su_Append(n,p,su);
su[length(su)] := ']';
writeln(su);
2015-02-20 09:02:09 -05:00
end;
procedure AmPairOutput(cnt:tValue);
var
i : tValue;
2015-11-18 06:14:39 +00:00
r_max,r_min,r : double;
2015-02-20 09:02:09 -05:00
begin
2015-11-18 06:14:39 +00:00
r_max := 1.0;
r_min := 16.0;
2015-02-20 09:02:09 -05:00
For i := 0 to cnt-1 do
2015-11-18 06:14:39 +00:00
with Indices[i] do
begin
2015-02-20 09:02:09 -05:00
r := IdxS/IDxI;
2015-11-18 06:14:39 +00:00
writeln(i+1:4,IdxI:16,IDxS:16,' ratio ',r:10:7);
IF r < 1 then
2015-02-20 09:02:09 -05:00
begin
2015-11-18 06:14:39 +00:00
writeln(i);
readln;
halt;
2015-02-20 09:02:09 -05:00
end;
2015-11-18 06:14:39 +00:00
if r_max < r then
r_max := r
else
if r_min > r then
r_min := r;
IF cnt < 20 then
2015-02-20 09:02:09 -05:00
begin
2015-11-18 06:14:39 +00:00
ProperDivs(IdxI);
ProperDivs(IdxS);
2015-02-20 09:02:09 -05:00
end;
end;
2015-11-18 06:14:39 +00:00
writeln(' min ratio ',r_min:12:10); writeln(' max ratio ',r_max:12:10);
2015-02-20 09:02:09 -05:00
end;
2015-11-18 06:14:39 +00:00
procedure SumOFProperDiv(n: tValue;var SumOfProperDivs:tValue);
// calculated by prime factorization
2015-02-20 09:02:09 -05:00
var
2015-11-18 06:14:39 +00:00
i,q, primNo, Prime,pot : tValue;
SumOfDivs: tValue;
2015-02-20 09:02:09 -05:00
begin
2015-11-18 06:14:39 +00:00
i := N;
SumOfDivs := 1;
primNo := 0;
Prime := Primes[0];
q := i DIV Prime;
2015-02-20 09:02:09 -05:00
repeat
2015-11-18 06:14:39 +00:00
if q*Prime = i then
Begin
pot := 1;
repeat
i := q;
q := i div Prime;
Pot := Pot * Prime+1;
until q*Prime <> i;
SumOfDivs := SumOfDivs * pot;
end;
Inc(primNo);
Prime := Primes[primNo];
q := i DIV Prime;
{check if i already prime}
if Prime > q then
2015-02-20 09:02:09 -05:00
begin
2015-11-18 06:14:39 +00:00
prime := i;
q := 1;
2015-02-20 09:02:09 -05:00
end;
2015-11-18 06:14:39 +00:00
until i = 1;
SumOfProperDivs := SumOfDivs - N;
2015-02-20 09:02:09 -05:00
end;
2015-11-18 06:14:39 +00:00
function Check:tValue;
const
//going backwards
DIV23 : array[0..5] of byte =
//== 5,4,3,2,1,0
(1,0,0,0,1,0);
2015-02-20 09:02:09 -05:00
var
2015-11-18 06:14:39 +00:00
i,s,k,n : tValue;
idx : nativeInt;
2015-02-20 09:02:09 -05:00
begin
2015-11-18 06:14:39 +00:00
n := 0;
idx := 3;
For i := 2 to MAX do
2015-02-20 09:02:09 -05:00
begin
2015-11-18 06:14:39 +00:00
//must be divisble by 2 or 3 ( n < High(tValue) < 1e14 )
IF DIV23[idx] = 0 then
2015-02-20 09:02:09 -05:00
begin
2015-11-18 06:14:39 +00:00
SumOFProperDiv(i,s);
//only 24.7...%
IF s>i then
Begin
SumOFProperDiv(s,k);
IF k = i then
begin
With indices[n] do
begin
idxI := i;
idxS := s;
end;
inc(n);
end;
end;
2015-02-20 09:02:09 -05:00
end;
2015-11-18 06:14:39 +00:00
dec(idx);
IF idx < 0 then
idx := high(DIV23);
2015-02-20 09:02:09 -05:00
end;
2015-11-18 06:14:39 +00:00
result := n;
2015-02-20 09:02:09 -05:00
end;
var
2015-11-18 06:14:39 +00:00
T2,T1: TDatetime;
2015-02-20 09:02:09 -05:00
APcnt: tValue;
begin
2015-11-18 06:14:39 +00:00
InitPrimes;
2015-02-20 09:02:09 -05:00
T1:= time;
2015-11-18 06:14:39 +00:00
APCnt:= Check;
2015-02-20 09:02:09 -05:00
T2:= time;
AmPairOutput(APCnt);
writeln('Time to find amicable pairs ',FormatDateTime('HH:NN:SS.ZZZ' ,T2-T1));
2015-11-18 06:14:39 +00:00
{$IFNDEF UNIX} readln;{$ENDIF}
2015-02-20 09:02:09 -05:00
end.