Added integer factorization and enumeration of dividers
This commit is contained in:
parent
cccf5693f7
commit
a034fbaedc
|
@ -22,7 +22,7 @@ unit UNumberTheory;
|
||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
Classes, SysUtils;
|
Classes, SysUtils, Generics.Collections, Math;
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
||||||
|
@ -34,6 +34,52 @@ type
|
||||||
class function LeastCommonMultiple(AValue1, AValue2: Int64): Int64;
|
class function LeastCommonMultiple(AValue1, AValue2: Int64): Int64;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
TInt64Array = array of Int64;
|
||||||
|
|
||||||
|
{ TIntegerFactor }
|
||||||
|
|
||||||
|
TIntegerFactor = record
|
||||||
|
Factor: Int64;
|
||||||
|
Exponent: Byte;
|
||||||
|
end;
|
||||||
|
|
||||||
|
TIntegerFactors = specialize TList<TIntegerFactor>;
|
||||||
|
|
||||||
|
{ TIntegerFactorization }
|
||||||
|
|
||||||
|
TIntegerFactorization = class
|
||||||
|
public
|
||||||
|
class function PollardsRhoAlgorithm(const AValue: Int64): TInt64Array;
|
||||||
|
class function GetNormalized(constref AIntegerFactorArray: TInt64Array): TIntegerFactors;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TDividersEnumerator }
|
||||||
|
|
||||||
|
TDividersEnumerator = class
|
||||||
|
private
|
||||||
|
FFactors: TIntegerFactors;
|
||||||
|
FCurrentExponents: array of Byte;
|
||||||
|
function GetCount: Integer;
|
||||||
|
public
|
||||||
|
constructor Create(constref AIntegerFactorArray: TInt64Array);
|
||||||
|
destructor Destroy; override;
|
||||||
|
function GetCurrent: Int64;
|
||||||
|
function MoveNext: Boolean;
|
||||||
|
procedure Reset;
|
||||||
|
property Current: Int64 read GetCurrent;
|
||||||
|
property Count: Integer read GetCount;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TDividers }
|
||||||
|
|
||||||
|
TDividers = class
|
||||||
|
private
|
||||||
|
FFactorArray: TInt64Array;
|
||||||
|
public
|
||||||
|
constructor Create(constref AIntegerFactorArray: TInt64Array);
|
||||||
|
function GetEnumerator: TDividersEnumerator;
|
||||||
|
end;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
{ TNumberTheory }
|
{ TNumberTheory }
|
||||||
|
@ -58,5 +104,177 @@ begin
|
||||||
Result := (Abs(AValue1) div GreatestCommonDivisor(AValue1, AValue2)) * Abs(AValue2);
|
Result := (Abs(AValue1) div GreatestCommonDivisor(AValue1, AValue2)) * Abs(AValue2);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ TIntegerFactorization }
|
||||||
|
|
||||||
|
// https://en.wikipedia.org/wiki/Pollard%27s_rho_algorithm
|
||||||
|
class function TIntegerFactorization.PollardsRhoAlgorithm(const AValue: Int64): TInt64Array;
|
||||||
|
var
|
||||||
|
primes: specialize TList<Int64>;
|
||||||
|
composites: specialize TStack<Int64>;
|
||||||
|
factor, n: Int64;
|
||||||
|
i: Integer;
|
||||||
|
|
||||||
|
function G(const AX, AC: Int64): Int64;
|
||||||
|
begin
|
||||||
|
Result := (AX * AX + AC) mod n;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function FindFactor(const AStartValue, AC: Int64): Int64;
|
||||||
|
var
|
||||||
|
x, y, d: Int64;
|
||||||
|
begin
|
||||||
|
x := AStartValue;
|
||||||
|
y := x;
|
||||||
|
d := 1;
|
||||||
|
while d = 1 do
|
||||||
|
begin
|
||||||
|
x := G(x, AC);
|
||||||
|
y := G(G(y, AC), AC);
|
||||||
|
d := TNumberTheory.GreatestCommonDivisor(Abs(x - y), n);
|
||||||
|
end;
|
||||||
|
Result := d;
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
primes := specialize TList<Int64>.Create;
|
||||||
|
composites := specialize TStack<Int64>.Create;
|
||||||
|
|
||||||
|
n := Abs(AValue);
|
||||||
|
while (n and 1) = 0 do
|
||||||
|
begin
|
||||||
|
primes.Add(2);
|
||||||
|
n := n shr 1;
|
||||||
|
end;
|
||||||
|
|
||||||
|
composites.Push(n);
|
||||||
|
while composites.Count > 0 do
|
||||||
|
begin
|
||||||
|
n := composites.Pop;
|
||||||
|
i := 0;
|
||||||
|
repeat
|
||||||
|
factor := FindFactor(2 + (i + 1) div 2, 1 - i div 2);
|
||||||
|
if factor < n then
|
||||||
|
begin
|
||||||
|
composites.Push(factor);
|
||||||
|
composites.Push(n div factor);
|
||||||
|
end;
|
||||||
|
Inc(i);
|
||||||
|
until (factor < n) or (i > 3);
|
||||||
|
if factor = n then
|
||||||
|
primes.Add(factor);
|
||||||
|
end;
|
||||||
|
|
||||||
|
Result := primes.ToArray;
|
||||||
|
|
||||||
|
primes.Free;
|
||||||
|
composites.Free;
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TIntegerFactorization.GetNormalized(constref AIntegerFactorArray: TInt64Array): TIntegerFactors;
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
factor: Int64;
|
||||||
|
normal: TIntegerFactor;
|
||||||
|
found: Boolean;
|
||||||
|
begin
|
||||||
|
Result := TIntegerFactors.Create;
|
||||||
|
for factor in AIntegerFactorArray do
|
||||||
|
begin
|
||||||
|
found := False;
|
||||||
|
for i := 0 to Result.Count - 1 do
|
||||||
|
if Result[i].Factor = factor then
|
||||||
|
begin
|
||||||
|
found := True;
|
||||||
|
normal := Result[i];
|
||||||
|
Inc(normal.Exponent);
|
||||||
|
Result[i] := normal;
|
||||||
|
Break;
|
||||||
|
end;
|
||||||
|
if not found then
|
||||||
|
begin
|
||||||
|
normal.Factor := factor;
|
||||||
|
normal.Exponent := 1;
|
||||||
|
Result.Add(normal);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TDividersEnumerator }
|
||||||
|
|
||||||
|
function TDividersEnumerator.GetCount: Integer;
|
||||||
|
var
|
||||||
|
factor: TIntegerFactor;
|
||||||
|
begin
|
||||||
|
if FFactors.Count > 0 then
|
||||||
|
begin
|
||||||
|
Result := 1;
|
||||||
|
for factor in FFactors do
|
||||||
|
Result := Result * factor.Exponent;
|
||||||
|
Dec(Result);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Result := 0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor TDividersEnumerator.Create(constref AIntegerFactorArray: TInt64Array);
|
||||||
|
begin
|
||||||
|
FFactors := TIntegerFactorization.GetNormalized(AIntegerFactorArray);
|
||||||
|
SetLength(FCurrentExponents, FFactors.Count);
|
||||||
|
end;
|
||||||
|
|
||||||
|
destructor TDividersEnumerator.Destroy;
|
||||||
|
begin
|
||||||
|
FFactors.Free;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TDividersEnumerator.GetCurrent: Int64;
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
Result := 1;
|
||||||
|
for i := Low(FCurrentExponents) to High(FCurrentExponents) do
|
||||||
|
if FCurrentExponents[i] > 0 then
|
||||||
|
Result := Result * Round(Power(FFactors[i].Factor, FCurrentExponents[i]));
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TDividersEnumerator.MoveNext: Boolean;
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
Result := False;
|
||||||
|
i := 0;
|
||||||
|
while (i <= High(FCurrentExponents)) and (FCurrentExponents[i] >= FFactors[i].Exponent) do
|
||||||
|
begin
|
||||||
|
FCurrentExponents[i] := 0;
|
||||||
|
Inc(i);
|
||||||
|
end;
|
||||||
|
|
||||||
|
if i <= High(FCurrentExponents) then
|
||||||
|
begin
|
||||||
|
Inc(FCurrentExponents[i]);
|
||||||
|
Result := True;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TDividersEnumerator.Reset;
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
for i := Low(FCurrentExponents) to High(FCurrentExponents) do
|
||||||
|
FCurrentExponents[i] := 0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TDividers }
|
||||||
|
|
||||||
|
constructor TDividers.Create(constref AIntegerFactorArray: TInt64Array);
|
||||||
|
begin
|
||||||
|
FFactorArray := AIntegerFactorArray;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TDividers.GetEnumerator: TDividersEnumerator;
|
||||||
|
begin
|
||||||
|
Result := TDividersEnumerator.Create(FFactorArray);
|
||||||
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue