Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 41 additions & 69 deletions PrimeDelphi/solution_1/PrimePas.dpr
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,20 @@ uses
Math,
Windows;

var
MyDict : TDictionary<NativeInt, NativeInt>;

type

TPrimeSieve = class
private
FSieveSize: NativeInt;
FSieveSize2: NativeInt;
FSieveSizeSqrt: NativeInt;
FBitArray: array of ByteBool; //ByteBool: 4644. WordBool: 4232. LongBool: 3673
FMyDict: TDictionary<NativeInt, NativeInt>;
FBitArray: array of ByteBool;

procedure InitializeBits;
public
constructor Create(Size: Integer);
destructor Destroy; override;

procedure RunSieve; // Calculate the primes up to the specified limit

Expand All @@ -48,82 +49,26 @@ begin
//The optimization here is that we only store bits for *odd* numbers.
// So FBitArray[3] is if 3 is prime
// and FBitArray[4] is if 5 is prime
//GetBit and SetBit do the work of "div 2"
SetLength(FBitArray, FSieveSize2);
InitializeBits;

FMyDict := TDictionary<NativeInt, NativeInt>.Create;

// Historical data for validating our results - the number of primes
// to be found under some limit, such as 168 primes under 1000
FMyDict.Add( 10, 4); //nobody noticed that 1 is wrong? [2, 3, 5, 7]
FMyDict.Add( 100, 25);
FMyDict.Add( 1000, 168);
FMyDict.Add( 10000, 1229);
FMyDict.Add( 100000, 9592);
FMyDict.Add( 1000000, 78498);
FMyDict.Add( 10000000, 664579);
FMyDict.Add(100000000, 5761455);
end;

destructor TPrimeSieve.Destroy;
begin
FreeAndNil(FMyDict);

inherited;
end;

function TPrimeSieve.CountPrimes: Integer;
var
count: NativeInt;
i: NativeInt;
begin
count := 0;
Result := 0;
for i := 0 to High(FBitArray) do
begin
if FBitArray[i] then
Inc(count);
end;

Result := count;
if (not FBitArray[i]) then Inc(Result); // remember logic is reversed
end;

function TPrimeSieve.ValidateResults: Boolean;
begin
if FMyDict.ContainsKey(FSieveSize) then
Result := FMyDict[FSieveSize] = Self.CountPrimes
if MyDict.ContainsKey(FSieveSize) then
Result := MyDict[FSieveSize] = Self.CountPrimes
else
Result := False;
end;

procedure TPrimeSieve.InitializeBits;
var
i: NativeInt;
remaining: NativeInt;
begin
remaining := Length(FBitArray);
i := 0;
while remaining >= 8 do
begin
FBitArray[i] := True;
FBitArray[i+1] := True;
FBitArray[i+2] := True;
FBitArray[i+3] := True;
FBitArray[i+4] := True;
FBitArray[i+5] := True;
FBitArray[i+6] := True;
FBitArray[i+7] := True;
Inc(i, 8);
Dec(remaining, 8);
end;
while remaining > 0 do
begin
FBitArray[i] := True;
Inc(i);
Dec(remaining);
end;
end;

procedure TPrimeSieve.RunSieve;
var
num: NativeInt;
Expand All @@ -136,9 +81,9 @@ begin
begin
r:=factor AND $1;
num:=factor SHR 1;
while num<FSieveSize2 do
while num<FSieveSizeSqrt do
begin
if FBitArray[num] then
if (not FBitArray[num]) then // logic is reversed to avoid initializer
begin
factor := (num SHL 1) OR r;
Break;
Expand All @@ -150,7 +95,7 @@ begin
num := factor*3 SHR 1;
while num<=FSieveSize2 do
begin
FBitArray[num]:=False;
FBitArray[num]:=true; // logic is reversed.
Inc(num,factor);
end;

Expand All @@ -173,7 +118,7 @@ begin
begin
if (num and $1 = $1) then
begin
if FBitArray[num div 2] then
if not FBitArray[num div 2] then
begin
if ShowResults then
Write(IntToStr(num) + ', ');
Expand All @@ -200,7 +145,7 @@ begin
passes := 0;

sieve := nil;
while TTimeSpan.Subtract(Now, dtStart).TotalSeconds < 10 do
while TTimeSpan.Subtract(Now, dtStart).TotalSeconds < 5 do
begin
if Assigned(sieve) then
sieve.Free;
Expand All @@ -215,6 +160,22 @@ begin
sieve.PrintResults(False, tD.TotalSeconds, passes);
end;

Procedure InitStaticDictionary;
begin
MyDict := TDictionary<NativeInt, NativeInt>.Create;

// Historical data for validating our results - the number of primes
// to be found under some limit, such as 168 primes under 1000
MyDict.Add( 10, 4); //nobody noticed that 1 is wrong? [2, 3, 5, 7]
MyDict.Add( 100, 25);
MyDict.Add( 1000, 168);
MyDict.Add( 10000, 1229);
MyDict.Add( 100000, 9592);
MyDict.Add( 1000000, 78498);
MyDict.Add( 10000000, 664579);
MyDict.Add(100000000, 5761455);
end;

{
Intel Core i5-9400 @ 2.90 GHz
- 32-bit: 4,809 passes
Expand All @@ -233,9 +194,20 @@ end;
- 64-bit: DEAD SLOW of some reason
Further optimizations:
- 32-bit: 8,600+ passes

Optimization of Kim's code by glenkleidon
- Made the History class static (as it is in the c++ because define as a const)
- The initializer for Delphi ByteBool by default sets to false
previous implementation initialized every value to true first,
but a better optimization is to simply reverse the logic - false = true/
true=false so there is no need to initialize the array.
Techically Delphi could have used a call to
FillChar(FBitArray[0],FSieveSize2,1);
but dynamic arrays MAY not be contiguous and therefore not safe.
}
begin
try
InitStaticDictionary;
Main;
WriteLn('Press enter to close...');
Readln;
Expand Down