diff --git a/PrimeDelphi/solution_1/PrimePas.dpr b/PrimeDelphi/solution_1/PrimePas.dpr index 601964672..4011f7f14 100644 --- a/PrimeDelphi/solution_1/PrimePas.dpr +++ b/PrimeDelphi/solution_1/PrimePas.dpr @@ -13,19 +13,20 @@ uses Math, Windows; +var + MyDict : TDictionary; + type + TPrimeSieve = class private FSieveSize: NativeInt; FSieveSize2: NativeInt; FSieveSizeSqrt: NativeInt; - FBitArray: array of ByteBool; //ByteBool: 4644. WordBool: 4232. LongBool: 3673 - FMyDict: TDictionary; + FBitArray: array of ByteBool; - procedure InitializeBits; public constructor Create(Size: Integer); - destructor Destroy; override; procedure RunSieve; // Calculate the primes up to the specified limit @@ -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.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; @@ -136,9 +81,9 @@ begin begin r:=factor AND $1; num:=factor SHR 1; - while num.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 @@ -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;