Fixed TBigInt heap memory allocation (fixed memory leaks)
This commit is contained in:
parent
bfb33673ee
commit
5a3c320942
168
UBigInt.pas
168
UBigInt.pas
|
@ -29,20 +29,36 @@ type
|
||||||
|
|
||||||
{ TBigInt }
|
{ TBigInt }
|
||||||
|
|
||||||
// This is an abbreviated reimplementation of a C# class created in 2022.
|
// This is an abbreviated reimplementation in Freepascal of a C# class created in 2022.
|
||||||
TBigInt = object
|
TBigInt = object
|
||||||
private
|
private
|
||||||
FDigits: TDigits;
|
FDigits: TDigits;
|
||||||
FIsNegative: Boolean;
|
FIsNegative: Boolean;
|
||||||
|
|
||||||
|
// Copies consecutive digits from this BigInt to create a new one. The result will be positive. Leading zeros are
|
||||||
|
// removed from the result, but AIndex + ACount must not exceed the number of digits of this BigInt.
|
||||||
|
// AIndex is the first (least significant) digit to be taken. The digit with this index will become the 0th digit of
|
||||||
|
// the new BigInt.
|
||||||
|
// ACount is the number of consecutive digits to be taken, and the number of digits of the result.
|
||||||
|
function GetSegment(const AIndex, ACount: Integer): TBigInt;
|
||||||
|
|
||||||
|
// Compares the absolute value of this TBigInt object to the absolute value of another one. Returns -1 if this
|
||||||
|
// object is less than AOther, 1 if this object is greater than AOther, and 0 if they are equal.
|
||||||
|
function CompareToAbsoluteValues(constref AOther: TBigInt): Integer;
|
||||||
|
|
||||||
|
class function GetZero: TBigInt; static;
|
||||||
|
|
||||||
// Adds A and B, ignoring their signs and using ReturnNegative instead. The result is
|
// Adds A and B, ignoring their signs and using ReturnNegative instead. The result is
|
||||||
// Sign * (Abs(A) + Abs(B)),
|
// Sign * (Abs(A) + Abs(B)),
|
||||||
// where Sign is 1 for ReturnNegative = False and -1 otherwise.
|
// where Sign is 1 for ReturnNegative = False and -1 otherwise.
|
||||||
class function AddAbsoluteValues(constref AA, AB: TBigInt; const AReturnNegative: Boolean): TBigInt; static;
|
class function AddAbsoluteValues(constref AA, AB: TBigInt; const AReturnNegative: Boolean): TBigInt; static;
|
||||||
|
|
||||||
// Subtracts B from A, ignoring their signs. However, the result might be negative, and the sign can be reversed by
|
// Subtracts B from A, ignoring their signs. However, the result might be negative, and the sign can be reversed by
|
||||||
// setting ReturnNegative to True. The result is
|
// setting ReturnNegative to True. The result is
|
||||||
// Sign * (Abs(A) - Abs(B)),
|
// Sign * (Abs(A) - Abs(B)),
|
||||||
// where Sign is 1 for ReturnNegative = False and -1 otherwise.
|
// where Sign is 1 for ReturnNegative = False and -1 otherwise.
|
||||||
class function SubtractAbsoluteValues(constref AA, AB: TBigInt; const AReturnNegative: Boolean): TBigInt; static;
|
class function SubtractAbsoluteValues(constref AA, AB: TBigInt; const AReturnNegative: Boolean): TBigInt; static;
|
||||||
|
|
||||||
// Multiplies A and B, ignoring their signs and using ReturnNegative instead. This multiplication uses a recursive
|
// Multiplies A and B, ignoring their signs and using ReturnNegative instead. This multiplication uses a recursive
|
||||||
// implementation of the Karatsuba algorithm. See
|
// implementation of the Karatsuba algorithm. See
|
||||||
// https://www.geeksforgeeks.org/karatsuba-algorithm-for-fast-multiplication-using-divide-and-conquer-algorithm/
|
// https://www.geeksforgeeks.org/karatsuba-algorithm-for-fast-multiplication-using-divide-and-conquer-algorithm/
|
||||||
|
@ -50,21 +66,11 @@ type
|
||||||
// Sign * (Abs(a) * Abs(b))
|
// Sign * (Abs(a) * Abs(b))
|
||||||
// where Sign is 1 for ReturnNegative = False and -1 otherwise.
|
// where Sign is 1 for ReturnNegative = False and -1 otherwise.
|
||||||
class function MultiplyAbsoluteValues(constref AA, AB: TBigInt; const AReturnNegative: Boolean): TBigInt; static;
|
class function MultiplyAbsoluteValues(constref AA, AB: TBigInt; const AReturnNegative: Boolean): TBigInt; static;
|
||||||
// Copies consecutive digits from this BigInt to create a new one. The result will be positive. Leading zeros are
|
|
||||||
// removed from the result, but AIndex + ACount must not exceed the number of digits of this BigInt.
|
|
||||||
// AIndex is the first (least significant) digit to be taken. The digit with this index will become the 0th digit of
|
|
||||||
// the new BigInt.
|
|
||||||
// ACount is the number of consecutive digits to be taken, and the number of digits of the result.
|
|
||||||
function GetSegment(const AIndex, ACount: Integer): TBigInt;
|
|
||||||
// Compares the absolute value of this TBigInt object to the absolute value of another one. Returns -1 if this
|
|
||||||
// object is less than AOther, 1 if this object is greater than AOther, and 0 if they are equal.
|
|
||||||
function CompareToAbsoluteValues(constref AOther: TBigInt): Integer;
|
|
||||||
public
|
public
|
||||||
property IsNegative: Boolean read FIsNegative;
|
property IsNegative: Boolean read FIsNegative;
|
||||||
constructor InitZero;
|
class property Zero: TBigInt read GetZero;
|
||||||
constructor Init(const AValue: Int64);
|
|
||||||
destructor Done;
|
|
||||||
function CompareTo(constref AOther: TBigInt): Integer;
|
function CompareTo(constref AOther: TBigInt): Integer;
|
||||||
|
class function FromInt64(const AValue: Int64): TBigInt; static;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
operator := (const A: Int64): TBigInt;
|
operator := (const A: Int64): TBigInt;
|
||||||
|
@ -84,8 +90,48 @@ const
|
||||||
CHalfBits = CBitsPerDigit >> 1;
|
CHalfBits = CBitsPerDigit >> 1;
|
||||||
CHalfDigitMax = (1 << CHalfBits) - 1;
|
CHalfDigitMax = (1 << CHalfBits) - 1;
|
||||||
|
|
||||||
|
CZero: TBigInt = (FDigits: (0); FIsNegative: False);
|
||||||
|
|
||||||
{ TBigInt }
|
{ TBigInt }
|
||||||
|
|
||||||
|
function TBigInt.GetSegment(const AIndex, ACount: Integer): TBigInt;
|
||||||
|
var
|
||||||
|
trimmedCount: Integer;
|
||||||
|
begin
|
||||||
|
trimmedCount := ACount;
|
||||||
|
while (trimmedCount > 1) and (FDigits[AIndex + trimmedCount - 1] = 0) do
|
||||||
|
Dec(trimmedCount);
|
||||||
|
SetLength(Result.FDigits, trimmedCount);
|
||||||
|
Move(FDigits[AIndex], Result.FDigits[0], CDigitSize * trimmedCount);
|
||||||
|
Result.FIsNegative := False;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TBigInt.CompareToAbsoluteValues(constref AOther: TBigInt): Integer;
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
Result := Length(FDigits) - Length(AOther.FDigits);
|
||||||
|
if Result = 0 then
|
||||||
|
begin
|
||||||
|
for i := High(FDigits) downto 0 do
|
||||||
|
if FDigits[i] < AOther.FDigits[i] then
|
||||||
|
begin
|
||||||
|
Result := -1;
|
||||||
|
Break;
|
||||||
|
end
|
||||||
|
else if FDigits[i] > AOther.FDigits[i] then
|
||||||
|
begin
|
||||||
|
Result := 1;
|
||||||
|
Break;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TBigInt.GetZero: TBigInt;
|
||||||
|
begin
|
||||||
|
Result := CZero;
|
||||||
|
end;
|
||||||
|
|
||||||
class function TBigInt.AddAbsoluteValues(constref AA, AB: TBigInt; const AReturnNegative: Boolean): TBigInt;
|
class function TBigInt.AddAbsoluteValues(constref AA, AB: TBigInt; const AReturnNegative: Boolean): TBigInt;
|
||||||
var
|
var
|
||||||
i, lenA, lenB, len, shorter: Integer;
|
i, lenA, lenB, len, shorter: Integer;
|
||||||
|
@ -245,7 +291,7 @@ begin
|
||||||
begin
|
begin
|
||||||
if (AA.FDigits[0] <= CHalfDigitMax) and (AB.FDigits[0] <= CHalfDigitMax) then
|
if (AA.FDigits[0] <= CHalfDigitMax) and (AB.FDigits[0] <= CHalfDigitMax) then
|
||||||
if (AA.FDigits[0] = 0) or (AB.FDigits[0] = 0) then
|
if (AA.FDigits[0] = 0) or (AB.FDigits[0] = 0) then
|
||||||
Result.InitZero
|
Result := Zero
|
||||||
else begin
|
else begin
|
||||||
Result.FDigits := TDigits.Create(AA.FDigits[0] * AB.FDigits[0]);
|
Result.FDigits := TDigits.Create(AA.FDigits[0] * AB.FDigits[0]);
|
||||||
Result.FIsNegative := AReturnNegative;
|
Result.FIsNegative := AReturnNegative;
|
||||||
|
@ -267,8 +313,8 @@ begin
|
||||||
Result.FIsNegative := AReturnNegative;
|
Result.FIsNegative := AReturnNegative;
|
||||||
|
|
||||||
// The result of (a1 + a0) * (b1 + b0) might not fit in one digit, so one last recursion step is necessary.
|
// The result of (a1 + a0) * (b1 + b0) might not fit in one digit, so one last recursion step is necessary.
|
||||||
am.Init(a1 + a0);
|
am := FromInt64(a1 + a0);
|
||||||
bm.Init(b1 + b0);
|
bm := FromInt64(b1 + b0);
|
||||||
middle := (MultiplyAbsoluteValues(am, bm, False) - a1b1 - a0b0) << CHalfBits;
|
middle := (MultiplyAbsoluteValues(am, bm, False) - a1b1 - a0b0) << CHalfBits;
|
||||||
if AReturnNegative then
|
if AReturnNegative then
|
||||||
Result := Result - middle
|
Result := Result - middle
|
||||||
|
@ -312,86 +358,48 @@ begin
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TBigInt.GetSegment(const AIndex, ACount: Integer): TBigInt;
|
function TBigInt.CompareTo(constref AOther: TBigInt): Integer;
|
||||||
var
|
|
||||||
trimmedCount: Integer;
|
|
||||||
begin
|
begin
|
||||||
trimmedCount := ACount;
|
if FIsNegative = AOther.FIsNegative then
|
||||||
while (trimmedCount > 1) and (FDigits[AIndex + trimmedCount - 1] = 0) do
|
Result := CompareToAbsoluteValues(AOther)
|
||||||
Dec(trimmedCount);
|
else
|
||||||
SetLength(Result.FDigits, trimmedCount);
|
|
||||||
Move(FDigits[AIndex], Result.FDigits[0], CDigitSize * trimmedCount);
|
|
||||||
Result.FIsNegative := False;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TBigInt.CompareToAbsoluteValues(constref AOther: TBigInt): Integer;
|
|
||||||
var
|
|
||||||
i: Integer;
|
|
||||||
begin
|
|
||||||
if Length(FDigits) < Length(AOther.FDigits) then
|
|
||||||
Result := -1
|
|
||||||
else if Length(FDigits) > Length(AOther.FDigits) then
|
|
||||||
Result := 1
|
|
||||||
else begin
|
|
||||||
Result := 0;
|
|
||||||
for i := High(FDigits) downto 0 do
|
|
||||||
if FDigits[i] < AOther.FDigits[i] then
|
|
||||||
begin
|
|
||||||
Result := -1;
|
|
||||||
Break;
|
|
||||||
end
|
|
||||||
else if FDigits[i] > AOther.FDigits[i] then
|
|
||||||
begin
|
|
||||||
Result := 1;
|
Result := 1;
|
||||||
Break;
|
if FIsNegative then
|
||||||
end;
|
Result := -Result;
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
constructor TBigInt.InitZero;
|
class function TBigInt.FromInt64(const AValue: Int64): TBigInt;
|
||||||
begin
|
|
||||||
FIsNegative := False;
|
|
||||||
FDigits := TDigits.Create(0);
|
|
||||||
end;
|
|
||||||
|
|
||||||
constructor TBigInt.Init(const AValue: Int64);
|
|
||||||
var
|
var
|
||||||
absVal: Int64;
|
absVal: Int64;
|
||||||
begin
|
begin
|
||||||
FIsNegative := AValue < 0;
|
|
||||||
if AValue <> Int64.MinValue then
|
if AValue <> Int64.MinValue then
|
||||||
begin
|
begin
|
||||||
absVal := Abs(AValue);
|
absVal := Abs(AValue);
|
||||||
if absVal >= CBase then
|
if absVal >= CBase then
|
||||||
FDigits := TDigits.Create(absVal mod CBase, absVal div CBase)
|
Result.FDigits := TDigits.Create(absVal mod CBase, absVal div CBase)
|
||||||
else
|
else
|
||||||
FDigits := TDigits.Create(absVal);
|
Result.FDigits := TDigits.Create(absVal);
|
||||||
|
Result.FIsNegative := AValue < 0;
|
||||||
end
|
end
|
||||||
else begin
|
else begin
|
||||||
FIsNegative := True;
|
Result.FDigits := TDigits.Create(0, 1 << 31);
|
||||||
FDigits := TDigits.Create(0, 1 << 31);
|
Result.FIsNegative := True;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
destructor TBigInt.Done;
|
|
||||||
begin
|
|
||||||
SetLength(FDigits, 0);
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TBigInt.CompareTo(constref AOther: TBigInt): Integer;
|
|
||||||
begin
|
|
||||||
if IsNegative = AOther.IsNegative then
|
|
||||||
Result := CompareToAbsoluteValues(AOther)
|
|
||||||
else
|
|
||||||
Result := 1;
|
|
||||||
if IsNegative then
|
|
||||||
Result := -Result;
|
|
||||||
end;
|
|
||||||
|
|
||||||
operator := (const A: Int64): TBigInt;
|
operator := (const A: Int64): TBigInt;
|
||||||
begin
|
begin
|
||||||
Result.Done;
|
Result := TBigInt.FromInt64(A);
|
||||||
Result.Init(A);
|
end;
|
||||||
|
|
||||||
|
operator - (const A: TBigInt): TBigInt;
|
||||||
|
var
|
||||||
|
len: Integer;
|
||||||
|
begin
|
||||||
|
len := Length(A.FDigits);
|
||||||
|
SetLength(Result.FDigits, len);
|
||||||
|
Move(A.FDigits[0], Result.FDigits[0], len);
|
||||||
|
Result.FIsNegative := not A.FIsNegative;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
operator + (const A, B: TBigInt): TBigInt;
|
operator + (const A, B: TBigInt): TBigInt;
|
||||||
|
@ -412,8 +420,8 @@ end;
|
||||||
|
|
||||||
operator * (const A: TBigInt; const B: Int64): TBigInt;
|
operator * (const A: TBigInt; const B: Int64): TBigInt;
|
||||||
begin
|
begin
|
||||||
if (a = 0) or (b = 0) then
|
if (A = 0) or (B = 0) then
|
||||||
Result.InitZero
|
Result := TBigInt.Zero
|
||||||
else
|
else
|
||||||
Result := TBigInt.MultiplyAbsoluteValues(A, B, A.IsNegative = (B > 0));
|
Result := TBigInt.MultiplyAbsoluteValues(A, B, A.IsNegative = (B > 0));
|
||||||
end;
|
end;
|
||||||
|
@ -425,7 +433,7 @@ var
|
||||||
begin
|
begin
|
||||||
// Handles shift of zero.
|
// Handles shift of zero.
|
||||||
if A = 0 then
|
if A = 0 then
|
||||||
Result.InitZero
|
Result := TBigInt.Zero
|
||||||
else begin
|
else begin
|
||||||
// Determines full digit shifts and bit shifts.
|
// Determines full digit shifts and bit shifts.
|
||||||
DivMod(B, CBitsPerDigit, digitShifts, bitShifts);
|
DivMod(B, CBitsPerDigit, digitShifts, bitShifts);
|
||||||
|
|
Loading…
Reference in New Issue