398 lines
8 KiB
ObjectPascal
398 lines
8 KiB
ObjectPascal
program primesieve;
|
|
// sieving small ranges of 65536
|
|
//{$O+,R+}
|
|
{$IFDEF FPC}
|
|
{$MODE DELPHI}{$OPTIMIZATION ON,ALL}{$CODEALIGN proc=32}
|
|
uses
|
|
sysutils;
|
|
{$ENDIF}
|
|
{$IFDEF WINDOWS}
|
|
{$APPTYPE CONSOLE}
|
|
{$ENDIF}
|
|
|
|
const
|
|
smlPrimes :array [0..10] of Byte = (2,3,5,7,11,13,17,19,23,29,31);
|
|
maxPreSievePrime = 17;
|
|
sieveSize = 1 shl 15;//32768*2 ->max count of FoundPrimes = 6542
|
|
type
|
|
tSievePrim = record
|
|
svdeltaPrime:word;//diff between actual and new prime
|
|
svSivOfs:word;//-> sieveSize< 1 shl 16
|
|
svSivNum:LongWord;// 1 shl (16+32) = 2.8e14
|
|
end;
|
|
var
|
|
{$Align 16}
|
|
//primes up to 1E6-> sieving to 1E12
|
|
sievePrimes : array[0..78497] of tSievePrim;
|
|
{$Align 16}
|
|
preSieve :array[0..3*5*7*11*13*17-1] of Byte;
|
|
{$Align 16}
|
|
Sieve :array[0..sieveSize-1] of Byte;
|
|
{$Align 16}
|
|
FoundPrimes : array[0..6542] of LongWord;
|
|
{$Align 16}
|
|
Gaps : array[0..255] Of Uint64;
|
|
{$Align 16}
|
|
Limit,OffSet : Uint64;
|
|
|
|
SieveMaxIdx,
|
|
preSieveOffset,
|
|
SieveNum,
|
|
FoundPrimesCnt,
|
|
PrimPos,
|
|
LastInsertedSievePrime :NativeUInt;
|
|
|
|
procedure CopyPreSieveInSieve;forward;
|
|
procedure CollectPrimes;forward;
|
|
procedure sieveOneSieve;forward;
|
|
|
|
procedure preSieveInit;
|
|
var
|
|
i,pr,j,umf : NativeInt;
|
|
Begin
|
|
fillchar(preSieve[0],SizeOf(preSieve),#1);
|
|
i := 1;// starts with pr = 3
|
|
umf := 1;
|
|
repeat
|
|
IF preSieve[i] <> 0 then
|
|
Begin
|
|
pr := 2*i+1;
|
|
j := i;
|
|
repeat
|
|
preSieve[j] := 0;
|
|
inc(j,pr);
|
|
until j> High(preSieve);
|
|
umf := umf*pr;
|
|
end;
|
|
inc(i);
|
|
until umf>High(preSieve);
|
|
preSieveOffset := 0;
|
|
end;
|
|
|
|
procedure CalcSievePrimOfs(lmt:NativeUint);
|
|
var
|
|
i,pr : NativeUInt;
|
|
sq : Uint64;
|
|
begin
|
|
pr := 0;
|
|
i := 0;
|
|
repeat
|
|
with sievePrimes[i] do
|
|
Begin
|
|
pr := pr+svdeltaPrime;
|
|
IF sqr(pr) < (SieveSize*2) then
|
|
Begin
|
|
svSivNum := 0;
|
|
svSivOfs := (pr*pr-1) DIV 2;
|
|
end
|
|
else
|
|
Begin
|
|
SieveMaxIdx := i;
|
|
pr := pr-svdeltaPrime;
|
|
BREAK;
|
|
end;
|
|
end;
|
|
inc(i);
|
|
until i > lmt;
|
|
|
|
for i := i to lmt do
|
|
begin
|
|
with sievePrimes[i] do
|
|
Begin
|
|
pr := pr+svdeltaPrime;
|
|
sq := sqr(pr);
|
|
svSivNum := sq DIV (2*SieveSize);
|
|
svSivOfs := ( (sq - Uint64(svSivNum)*(2*SieveSize))-1)DIV 2;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure InitSieve;
|
|
begin
|
|
preSieveOffset := 0;
|
|
SieveNum :=0;
|
|
CalcSievePrimOfs(PrimPos-1);
|
|
end;
|
|
|
|
procedure InsertSievePrimes;
|
|
var
|
|
j :NativeUINt;
|
|
i,pr : NativeUInt;
|
|
begin
|
|
i := 0;
|
|
//ignore first primes already sieved with
|
|
if SieveNum = 0 then
|
|
repeat
|
|
inc(i);
|
|
until FoundPrimes[i] > maxPreSievePrime;
|
|
|
|
pr :=0;
|
|
j := Uint64(SieveNum)*SieveSize*2-LastInsertedSievePrime;
|
|
with sievePrimes[PrimPos] do
|
|
Begin
|
|
pr := FoundPrimes[i];
|
|
svdeltaPrime := pr+j;
|
|
j := pr;
|
|
end;
|
|
inc(PrimPos);
|
|
for i := i+1 to FoundPrimesCnt-1 do
|
|
Begin
|
|
IF PrimPos > High(sievePrimes) then
|
|
BREAK;
|
|
with sievePrimes[PrimPos] do
|
|
Begin
|
|
pr := FoundPrimes[i];
|
|
svdeltaPrime := (pr-j);
|
|
j := pr;
|
|
end;
|
|
inc(PrimPos);
|
|
end;
|
|
LastInsertedSievePrime :=Uint64(SieveNum)*(SieveSize*2)+pr;
|
|
end;
|
|
|
|
procedure sievePrimesInit;
|
|
var
|
|
i,j,pr:NativeInt;
|
|
Begin
|
|
LastInsertedSievePrime := 0;
|
|
|
|
PrimPos := 0;
|
|
preSieveOffset := 0;
|
|
SieveNum :=0;
|
|
CopyPreSieveInSieve;
|
|
i := 1; // start with 3
|
|
repeat
|
|
while Sieve[i] = 0 do
|
|
inc(i);
|
|
pr := 2*i+1;
|
|
inc(i);
|
|
j := ((pr*pr)-1) DIV 2;
|
|
if j > High(Sieve) then
|
|
BREAK;
|
|
repeat
|
|
Sieve[j] := 0;
|
|
inc(j,pr);
|
|
until j > High(Sieve);
|
|
until false;
|
|
|
|
CollectPrimes;
|
|
InsertSievePrimes;
|
|
IF PrimPos < High(sievePrimes) then
|
|
Begin
|
|
InitSieve;
|
|
//Erste Sieb nochmals, aber ohne Eintrag
|
|
CopyPreSieveInSieve;
|
|
sieveOneSieve;
|
|
repeat
|
|
inc(SieveNum);
|
|
CopyPreSieveInSieve;
|
|
sieveOneSieve;
|
|
CollectPrimes;
|
|
InsertSievePrimes;
|
|
until PrimPos > High(sievePrimes);
|
|
end;
|
|
end;
|
|
|
|
procedure OutGaps(g1,g2,delta:NativeUint);
|
|
begin
|
|
if g2= 0 then
|
|
writeln(2*g1:4,2*g1+2:4,delta:13,Gaps[g1]:13,Gaps[g1+1]:13)
|
|
else
|
|
writeln(2*g2-1:4,2*g1:4,delta:13,Gaps[g1-1]:13,Gaps[g1]:13);
|
|
end;
|
|
function GetDiffval(val1,val2: NativeInt): NativeInt;
|
|
begin
|
|
if val1*val2 = 0 then
|
|
EXIT(0);
|
|
dec(val1,val2);
|
|
if val1<0 then
|
|
val1 :=-val1;
|
|
GetDiffval := val1;
|
|
end;
|
|
|
|
procedure CheckGaps;
|
|
var
|
|
val1,val2,val3,i,DekaLimit : NativeInt;
|
|
Begin
|
|
writeln('Gap1 Gap2 difference first second prime');
|
|
dekaLimit := 10;
|
|
i := 1;
|
|
repeat
|
|
val1 := Gaps[i];
|
|
if val1 <> 0 then
|
|
Begin
|
|
val2 := GetDiffval(val1,Gaps[i-1]);
|
|
val3 := GetDiffval(val1,Gaps[i+1]);
|
|
while (val2>DekaLimit) or (val3>DekaLimit) do
|
|
begin
|
|
writeln(DekaLimit:21,'<');
|
|
if val2 = 0 then
|
|
begin
|
|
if val3 > 0 then
|
|
OutGaps(i,0,val3);
|
|
end
|
|
else
|
|
begin
|
|
if val3 = 0 then
|
|
OutGaps(i,1,val2)
|
|
else
|
|
Begin
|
|
if val3 > val2 then
|
|
OutGaps(i,0,val3)
|
|
else
|
|
OutGaps(i,1,val2);
|
|
end;
|
|
end;
|
|
DekaLimit := 10*DekaLimit;
|
|
end;
|
|
end;
|
|
inc(i);
|
|
until i>=254;
|
|
end;
|
|
|
|
procedure CopyPreSieveInSieve;
|
|
var
|
|
lmt : NativeInt;
|
|
Begin
|
|
lmt := preSieveOffset+sieveSize;
|
|
lmt := lmt-(High(preSieve)+1);
|
|
IF lmt<= 0 then
|
|
begin
|
|
Move(preSieve[preSieveOffset],Sieve[0],sieveSize);
|
|
if lmt <> 0 then
|
|
inc(preSieveOffset,sieveSize)
|
|
else
|
|
preSieveOffset := 0;
|
|
end
|
|
else
|
|
begin
|
|
Move(preSieve[preSieveOffset],Sieve[0],sieveSize-lmt);
|
|
Move(preSieve[0],Sieve[sieveSize-lmt],lmt);
|
|
preSieveOffset := lmt
|
|
end;
|
|
end;
|
|
|
|
procedure CollectPrimes;
|
|
var
|
|
pSieve : pbyte;
|
|
pFound : pLongWord;
|
|
i,idx : NativeInt;
|
|
Begin
|
|
pFound := @FoundPrimes[0];
|
|
idx := 0;
|
|
i := 0;
|
|
IF SieveNum = 0 then
|
|
Begin
|
|
repeat
|
|
pFound[idx] := smlPrimes[idx];
|
|
inc(idx);
|
|
until smlPrimes[idx]>maxPreSievePrime;
|
|
i := (smlPrimes[idx] -1) DIV 2;
|
|
end;
|
|
|
|
pSieve := @Sieve[0];
|
|
repeat
|
|
pFound[idx]:= 2*i+1;
|
|
inc(idx,pSieve[i]);
|
|
inc(i);
|
|
until i>High(Sieve);
|
|
FoundPrimesCnt:= idx;
|
|
end;
|
|
|
|
procedure sieveOneSieve;
|
|
var
|
|
i,j,pr,dSievNum :NativeUint;
|
|
Begin
|
|
pr := 0;
|
|
For i := 0 to SieveMaxIdx do
|
|
with sievePrimes[i] do
|
|
begin
|
|
pr := pr+svdeltaPrime;
|
|
IF svSivNum = sieveNum then
|
|
Begin
|
|
j := svSivOfs;
|
|
repeat
|
|
Sieve[j] := 0;
|
|
inc(j,pr);
|
|
until j > High(Sieve);
|
|
|
|
dSievNum := j DIV SieveSize;
|
|
svSivOfs := j-dSievNum*SieveSize;
|
|
inc(svSivNum,dSievNum);
|
|
end;
|
|
end;
|
|
|
|
i := SieveMaxIdx+1;
|
|
repeat
|
|
if i > High(SievePrimes) then
|
|
BREAK;
|
|
with sievePrimes[i] do
|
|
begin
|
|
if svSivNum > sieveNum then
|
|
Begin
|
|
SieveMaxIdx := I-1;
|
|
Break;
|
|
end;
|
|
pr := pr+svdeltaPrime;
|
|
j := svSivOfs;
|
|
repeat
|
|
Sieve[j] := 0;
|
|
inc(j,pr);
|
|
until j > High(Sieve);
|
|
dSievNum := j DIV SieveSize;
|
|
svSivOfs := j-dSievNum*SieveSize;
|
|
inc(svSivNum,dSievNum);
|
|
inc(i);
|
|
end;
|
|
until false;
|
|
end;
|
|
|
|
var
|
|
T1,T0,CNT,ActPrime,LastPrime,delta : Int64;
|
|
i: Int32;
|
|
|
|
begin
|
|
T0 := GetTickCount64;
|
|
Limit := 10*1000*1000*1000;//158*1000*1000*1000;
|
|
preSieveInit;
|
|
sievePrimesInit;
|
|
|
|
InitSieve;
|
|
offset := 0;
|
|
Cnt := 1;//==2
|
|
LastPrime := 2;
|
|
|
|
|
|
repeat
|
|
CopyPreSieveInSieve;sieveOneSieve;CollectPrimes;
|
|
inc(Cnt,FoundPrimesCnt);
|
|
//collect first occurrence of gap
|
|
i := 0;
|
|
repeat
|
|
ActPrime := Offset+FoundPrimes[i];
|
|
delta := (ActPrime - LastPrime) shr 1;
|
|
If Gaps[delta] = 0 then
|
|
Gaps[delta] := LastPrime;
|
|
LastPrime := ActPrime;
|
|
inc(i);
|
|
until (i >= FoundPrimesCnt);
|
|
|
|
inc(SieveNum);
|
|
inc(offset,2*SieveSize);
|
|
until SieveNum > (Limit DIV (2*SieveSize));
|
|
CheckGaps;
|
|
T1 := GetTickCount64;
|
|
OffSet := Uint64(SieveNum-1)*(2*SieveSize);
|
|
|
|
|
|
i := FoundPrimesCnt;
|
|
repeat
|
|
dec(i);
|
|
dec(cnt);
|
|
until (i = 0) OR (OffSet+FoundPrimes[i]<Limit);
|
|
writeln;
|
|
writeln(cnt,' in ',Limit,' takes ',T1-T0,' ms');
|
|
{$IFDEF WINDOWS}
|
|
writeln('Press <Enter>');readln;
|
|
{$ENDIF}
|
|
end.
|