Added more BigInt features and fixes
- Fixed some uses of Move - Added Sign, string initializers (hexadecimal and binary), explicit converter to Int64, comparison operators
This commit is contained in:
parent
eb2b4a3f99
commit
e11db7155a
155
UBigInt.pas
155
UBigInt.pas
|
@ -35,6 +35,8 @@ type
|
|||
FDigits: TDigits;
|
||||
FIsNegative: Boolean;
|
||||
|
||||
function GetSign: Integer;
|
||||
|
||||
// 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
|
||||
|
@ -66,11 +68,19 @@ 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;
|
||||
|
||||
class function FromHexOrBinString(const AValue: string; const AFromBase: Integer): TBigInt; static;
|
||||
class function ConvertDigitBlock(const AValue: string; var AStartIndex: Integer; const ACharBlockSize, AFromBase:
|
||||
Integer): Cardinal;
|
||||
public
|
||||
property IsNegative: Boolean read FIsNegative;
|
||||
property Sign: Integer read GetSign;
|
||||
class property Zero: TBigInt read GetZero;
|
||||
function CompareTo(constref AOther: TBigInt): Integer;
|
||||
function TryToInt64(out AOutput: Int64): Boolean;
|
||||
class function FromInt64(const AValue: Int64): TBigInt; static;
|
||||
class function FromHexadecimalString(const AValue: string): TBigInt; static;
|
||||
class function FromBinaryString(const AValue: string): TBigInt; static;
|
||||
end;
|
||||
|
||||
{ Operators }
|
||||
|
@ -83,6 +93,10 @@ type
|
|||
operator shl (const A: TBigInt; const B: Integer): TBigInt;
|
||||
operator = (const A, B: TBigInt): Boolean;
|
||||
operator <> (const A, B: TBigInt): Boolean;
|
||||
operator < (const A, B: TBigInt): Boolean;
|
||||
operator <= (const A, B: TBigInt): Boolean;
|
||||
operator > (const A, B: TBigInt): Boolean;
|
||||
operator >= (const A, B: TBigInt): Boolean;
|
||||
|
||||
implementation
|
||||
|
||||
|
@ -98,6 +112,16 @@ const
|
|||
|
||||
{ TBigInt }
|
||||
|
||||
function TBigInt.GetSign: Integer;
|
||||
begin
|
||||
if FIsNegative then
|
||||
Result := -1
|
||||
else if (Length(FDigits) > 1) or (FDigits[0] <> 0) then
|
||||
Result := 1
|
||||
else
|
||||
Result := 0;
|
||||
end;
|
||||
|
||||
function TBigInt.GetSegment(const AIndex, ACount: Integer): TBigInt;
|
||||
var
|
||||
trimmedCount: Integer;
|
||||
|
@ -105,8 +129,7 @@ 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.FDigits := Copy(FDigits, AIndex, trimmedCount);
|
||||
Result.FIsNegative := False;
|
||||
end;
|
||||
|
||||
|
@ -362,6 +385,65 @@ begin
|
|||
end;
|
||||
end;
|
||||
|
||||
class function TBigInt.FromHexOrBinString(const AValue: string; const AFromBase: Integer): TBigInt;
|
||||
var
|
||||
charBlockSize, offset, i, j, k, remainder: Integer;
|
||||
d: Cardinal;
|
||||
begin
|
||||
charBlockSize := 64 div AFromBase;
|
||||
if AValue[1] = '-' then
|
||||
begin
|
||||
offset := 2;
|
||||
Result.FIsNegative := True;
|
||||
end
|
||||
else begin
|
||||
offset := 1;
|
||||
Result.FIsNegative := False;
|
||||
end;
|
||||
|
||||
// Calculates the first (most significant) digit d of the result.
|
||||
DivMod(AValue.Length - offset, charBlockSize, i, remainder);
|
||||
k := offset;
|
||||
d := 0;
|
||||
// Checks the first block of chars that is not a full block.
|
||||
if remainder > 0 then
|
||||
d := ConvertDigitBlock(AValue, k, remainder, AFromBase);
|
||||
// Checks full blocks of chars for first digit.
|
||||
while (d = 0) and (i > 0) do
|
||||
begin
|
||||
Dec(i);
|
||||
d := ConvertDigitBlock(AValue, k, charBlockSize, AFromBase);
|
||||
end;
|
||||
|
||||
// Checks for zero.
|
||||
if (d = 0) and (i = 0) then
|
||||
Result := Zero
|
||||
else begin
|
||||
// Initializes the array of digits.
|
||||
SetLength(Result.FDigits, i + 1);
|
||||
Result.FDigits[i] := d;
|
||||
|
||||
// Calculates the other digits.
|
||||
for j := i - 1 downto 0 do
|
||||
Result.FDigits[j] := ConvertDigitBlock(AValue, k, charBlockSize, AFromBase);
|
||||
end;
|
||||
end;
|
||||
|
||||
class function TBigInt.ConvertDigitBlock(const AValue: string; var AStartIndex: Integer; const ACharBlockSize,
|
||||
AFromBase: Integer): Cardinal;
|
||||
var
|
||||
part: string;
|
||||
begin
|
||||
part := Copy(AValue, AStartIndex, ACharBlockSize);
|
||||
Inc(AStartIndex, ACharBlockSize);
|
||||
case AFromBase of
|
||||
2: part := '%' + part;
|
||||
8: part := '&' + part;
|
||||
16: part := '$' + part;
|
||||
end;
|
||||
Result := StrToDWord(part);
|
||||
end;
|
||||
|
||||
function TBigInt.CompareTo(constref AOther: TBigInt): Integer;
|
||||
begin
|
||||
if FIsNegative = AOther.FIsNegative then
|
||||
|
@ -372,6 +454,35 @@ begin
|
|||
Result := -Result;
|
||||
end;
|
||||
|
||||
function TBigInt.TryToInt64(out AOutput: Int64): Boolean;
|
||||
begin
|
||||
AOutput := 0;
|
||||
Result := False;
|
||||
case Length(FDigits) of
|
||||
0: Result := True;
|
||||
1: begin
|
||||
AOutput := FDigits[0];
|
||||
if FIsNegative then
|
||||
AOutput := -AOutput;
|
||||
Result := True;
|
||||
end;
|
||||
2: begin
|
||||
if FDigits[1] <= Integer.MaxValue then
|
||||
begin
|
||||
AOutput := FDigits[1] * CBase + FDigits[0];
|
||||
if FIsNegative then
|
||||
AOutput := -AOutput;
|
||||
Result := True;
|
||||
end
|
||||
else if (FDigits[1] = Integer.MaxValue + 1) and (FDigits[0] = 0) and FIsNegative then
|
||||
begin
|
||||
AOutput := Int64.MinValue;
|
||||
Result := True;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
class function TBigInt.FromInt64(const AValue: Int64): TBigInt;
|
||||
var
|
||||
absVal: Int64;
|
||||
|
@ -391,6 +502,16 @@ begin
|
|||
end;
|
||||
end;
|
||||
|
||||
class function TBigInt.FromHexadecimalString(const AValue: string): TBigInt;
|
||||
begin
|
||||
Result := FromHexOrBinString(AValue, 16);
|
||||
end;
|
||||
|
||||
class function TBigInt.FromBinaryString(const AValue: string): TBigInt;
|
||||
begin
|
||||
Result := FromHexOrBinString(AValue, 2);
|
||||
end;
|
||||
|
||||
{ Operators }
|
||||
|
||||
operator := (const A: Int64): TBigInt;
|
||||
|
@ -403,9 +524,13 @@ 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;
|
||||
if (len > 1) or (A.FDigits[0] > 0) then
|
||||
begin
|
||||
Result.FDigits := Copy(A.FDigits, 0, len);
|
||||
Result.FIsNegative := not A.FIsNegative;
|
||||
end
|
||||
else
|
||||
Result := TBigInt.Zero;
|
||||
end;
|
||||
|
||||
operator + (const A, B: TBigInt): TBigInt;
|
||||
|
@ -492,5 +617,25 @@ begin
|
|||
Result := A.CompareTo(B) <> 0;
|
||||
end;
|
||||
|
||||
operator < (const A, B: TBigInt): Boolean;
|
||||
begin
|
||||
Result := A.CompareTo(B) < 0;
|
||||
end;
|
||||
|
||||
operator <= (const A, B: TBigInt): Boolean;
|
||||
begin
|
||||
Result := A.CompareTo(B) <= 0;
|
||||
end;
|
||||
|
||||
operator > (const A, B: TBigInt): Boolean;
|
||||
begin
|
||||
Result := A.CompareTo(B) > 0;
|
||||
end;
|
||||
|
||||
operator >= (const A, B: TBigInt): Boolean;
|
||||
begin
|
||||
Result := A.CompareTo(B) >= 0;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
|
|
Loading…
Reference in New Issue