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 }
|
||||
|
||||
// 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
|
||||
private
|
||||
FDigits: TDigits;
|
||||
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
|
||||
// Sign * (Abs(A) + Abs(B)),
|
||||
// where Sign is 1 for ReturnNegative = False and -1 otherwise.
|
||||
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
|
||||
// setting ReturnNegative to True. The result is
|
||||
// Sign * (Abs(A) - Abs(B)),
|
||||
// where Sign is 1 for ReturnNegative = False and -1 otherwise.
|
||||
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
|
||||
// implementation of the Karatsuba algorithm. See
|
||||
// https://www.geeksforgeeks.org/karatsuba-algorithm-for-fast-multiplication-using-divide-and-conquer-algorithm/
|
||||
|
@ -50,21 +66,11 @@ type
|
|||
// Sign * (Abs(a) * Abs(b))
|
||||
// where Sign is 1 for ReturnNegative = False and -1 otherwise.
|
||||
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
|
||||
property IsNegative: Boolean read FIsNegative;
|
||||
constructor InitZero;
|
||||
constructor Init(const AValue: Int64);
|
||||
destructor Done;
|
||||
class property Zero: TBigInt read GetZero;
|
||||
function CompareTo(constref AOther: TBigInt): Integer;
|
||||
class function FromInt64(const AValue: Int64): TBigInt; static;
|
||||
end;
|
||||
|
||||
operator := (const A: Int64): TBigInt;
|
||||
|
@ -84,8 +90,48 @@ const
|
|||
CHalfBits = CBitsPerDigit >> 1;
|
||||
CHalfDigitMax = (1 << CHalfBits) - 1;
|
||||
|
||||
CZero: TBigInt = (FDigits: (0); FIsNegative: False);
|
||||
|
||||
{ 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;
|
||||
var
|
||||
i, lenA, lenB, len, shorter: Integer;
|
||||
|
@ -245,7 +291,7 @@ begin
|
|||
begin
|
||||
if (AA.FDigits[0] <= CHalfDigitMax) and (AB.FDigits[0] <= CHalfDigitMax) then
|
||||
if (AA.FDigits[0] = 0) or (AB.FDigits[0] = 0) then
|
||||
Result.InitZero
|
||||
Result := Zero
|
||||
else begin
|
||||
Result.FDigits := TDigits.Create(AA.FDigits[0] * AB.FDigits[0]);
|
||||
Result.FIsNegative := AReturnNegative;
|
||||
|
@ -267,8 +313,8 @@ begin
|
|||
Result.FIsNegative := AReturnNegative;
|
||||
|
||||
// The result of (a1 + a0) * (b1 + b0) might not fit in one digit, so one last recursion step is necessary.
|
||||
am.Init(a1 + a0);
|
||||
bm.Init(b1 + b0);
|
||||
am := FromInt64(a1 + a0);
|
||||
bm := FromInt64(b1 + b0);
|
||||
middle := (MultiplyAbsoluteValues(am, bm, False) - a1b1 - a0b0) << CHalfBits;
|
||||
if AReturnNegative then
|
||||
Result := Result - middle
|
||||
|
@ -312,86 +358,48 @@ begin
|
|||
end;
|
||||
end;
|
||||
|
||||
function TBigInt.GetSegment(const AIndex, ACount: Integer): TBigInt;
|
||||
var
|
||||
trimmedCount: Integer;
|
||||
function TBigInt.CompareTo(constref AOther: TBigInt): 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
|
||||
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
|
||||
if FIsNegative = AOther.FIsNegative then
|
||||
Result := CompareToAbsoluteValues(AOther)
|
||||
else
|
||||
Result := 1;
|
||||
Break;
|
||||
end;
|
||||
end;
|
||||
if FIsNegative then
|
||||
Result := -Result;
|
||||
end;
|
||||
|
||||
constructor TBigInt.InitZero;
|
||||
begin
|
||||
FIsNegative := False;
|
||||
FDigits := TDigits.Create(0);
|
||||
end;
|
||||
|
||||
constructor TBigInt.Init(const AValue: Int64);
|
||||
class function TBigInt.FromInt64(const AValue: Int64): TBigInt;
|
||||
var
|
||||
absVal: Int64;
|
||||
begin
|
||||
FIsNegative := AValue < 0;
|
||||
if AValue <> Int64.MinValue then
|
||||
begin
|
||||
absVal := Abs(AValue);
|
||||
if absVal >= CBase then
|
||||
FDigits := TDigits.Create(absVal mod CBase, absVal div CBase)
|
||||
Result.FDigits := TDigits.Create(absVal mod CBase, absVal div CBase)
|
||||
else
|
||||
FDigits := TDigits.Create(absVal);
|
||||
Result.FDigits := TDigits.Create(absVal);
|
||||
Result.FIsNegative := AValue < 0;
|
||||
end
|
||||
else begin
|
||||
FIsNegative := True;
|
||||
FDigits := TDigits.Create(0, 1 << 31);
|
||||
Result.FDigits := TDigits.Create(0, 1 << 31);
|
||||
Result.FIsNegative := True;
|
||||
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;
|
||||
begin
|
||||
Result.Done;
|
||||
Result.Init(A);
|
||||
Result := TBigInt.FromInt64(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;
|
||||
|
||||
operator + (const A, B: TBigInt): TBigInt;
|
||||
|
@ -412,8 +420,8 @@ end;
|
|||
|
||||
operator * (const A: TBigInt; const B: Int64): TBigInt;
|
||||
begin
|
||||
if (a = 0) or (b = 0) then
|
||||
Result.InitZero
|
||||
if (A = 0) or (B = 0) then
|
||||
Result := TBigInt.Zero
|
||||
else
|
||||
Result := TBigInt.MultiplyAbsoluteValues(A, B, A.IsNegative = (B > 0));
|
||||
end;
|
||||
|
@ -425,7 +433,7 @@ var
|
|||
begin
|
||||
// Handles shift of zero.
|
||||
if A = 0 then
|
||||
Result.InitZero
|
||||
Result := TBigInt.Zero
|
||||
else begin
|
||||
// Determines full digit shifts and bit shifts.
|
||||
DivMod(B, CBitsPerDigit, digitShifts, bitShifts);
|
||||
|
|
Loading…
Reference in New Issue