Merge branch 'bigint' into day24-analytical
This commit is contained in:
commit
6802da1743
159
UBigInt.pas
159
UBigInt.pas
|
@ -49,6 +49,7 @@ type
|
|||
function CompareToAbsoluteValues(constref AOther: TBigInt): Integer;
|
||||
|
||||
class function GetZero: TBigInt; static;
|
||||
class function GetOne: TBigInt; static;
|
||||
|
||||
// Adds A and B, ignoring their signs and using ReturnNegative instead. The result is
|
||||
// Sign * (Abs(A) + Abs(B)),
|
||||
|
@ -76,6 +77,7 @@ type
|
|||
property IsNegative: Boolean read FIsNegative;
|
||||
property Sign: Integer read GetSign;
|
||||
class property Zero: TBigInt read GetZero;
|
||||
class property One: TBigInt read GetOne;
|
||||
|
||||
// Returns the index of the most significant bit, i.e. returns integer k, where 2^k is the largest power of 2 that
|
||||
// is less than or equal to the absolute value of the number itself. Returns -1 if the given number is 0.
|
||||
|
@ -97,6 +99,7 @@ type
|
|||
operator - (const A, B: TBigInt): TBigInt;
|
||||
operator * (const A, B: TBigInt): TBigInt;
|
||||
operator shl (const A: TBigInt; const B: Integer): TBigInt;
|
||||
operator shr (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;
|
||||
|
@ -115,6 +118,7 @@ const
|
|||
CHalfDigitMax = (1 << CHalfBits) - 1;
|
||||
|
||||
CZero: TBigInt = (FDigits: (0); FIsNegative: False);
|
||||
COne: TBigInt = (FDigits: (1); FIsNegative: False);
|
||||
|
||||
{ TBigInt }
|
||||
|
||||
|
@ -165,6 +169,11 @@ begin
|
|||
Result := CZero;
|
||||
end;
|
||||
|
||||
class function TBigInt.GetOne: TBigInt;
|
||||
begin
|
||||
Result := COne;
|
||||
end;
|
||||
|
||||
class function TBigInt.AddAbsoluteValues(constref AA, AB: TBigInt; const AReturnNegative: Boolean): TBigInt;
|
||||
var
|
||||
i, j, lenA, lenB, len, shorter: Integer;
|
||||
|
@ -524,7 +533,7 @@ var
|
|||
i: Integer;
|
||||
begin
|
||||
if FIsNegative then
|
||||
Result := '-'
|
||||
Result := '(-'
|
||||
else
|
||||
Result := '';
|
||||
for i := 0 to Length(FDigits) - 2 do
|
||||
|
@ -532,6 +541,8 @@ begin
|
|||
Result := Result + IntToStr(FDigits[Length(FDigits) - 1]);
|
||||
for i := 0 to Length(FDigits) - 2 do
|
||||
Result := Result + ')';
|
||||
if FIsNegative then
|
||||
Result := Result + ')'
|
||||
end;
|
||||
|
||||
class function TBigInt.FromInt64(const AValue: Int64): TBigInt;
|
||||
|
@ -568,7 +579,6 @@ end;
|
|||
operator := (const A: Int64): TBigInt;
|
||||
begin
|
||||
Result := TBigInt.FromInt64(A);
|
||||
//WriteLn(':=a op: ', Result.ToString);
|
||||
end;
|
||||
|
||||
operator - (const A: TBigInt): TBigInt;
|
||||
|
@ -583,8 +593,6 @@ begin
|
|||
end
|
||||
else
|
||||
Result := TBigInt.Zero;
|
||||
//WriteLn(' a: ', A.ToString);
|
||||
//WriteLn('-a op: ', Result.ToString);
|
||||
end;
|
||||
|
||||
operator + (const A, B: TBigInt): TBigInt;
|
||||
|
@ -593,9 +601,6 @@ begin
|
|||
Result := TBigInt.AddAbsoluteValues(A, B, A.IsNegative)
|
||||
else
|
||||
Result := TBigInt.SubtractAbsoluteValues(A, B, A.IsNegative);
|
||||
//WriteLn(' a: ', A.ToString);
|
||||
//WriteLn(' b: ', B.ToString);
|
||||
//WriteLn('a+b op: ', Result.ToString);
|
||||
end;
|
||||
|
||||
operator - (const A, B: TBigInt): TBigInt;
|
||||
|
@ -604,9 +609,6 @@ begin
|
|||
Result := TBigInt.SubtractAbsoluteValues(A, B, A.IsNegative)
|
||||
else
|
||||
Result := TBigInt.AddAbsoluteValues(A, B, A.IsNegative);
|
||||
//WriteLn(' a: ', A.ToString);
|
||||
//WriteLn(' b: ', B.ToString);
|
||||
//WriteLn('a-b op: ', Result.ToString);
|
||||
end;
|
||||
|
||||
operator * (const A, B: TBigInt): TBigInt;
|
||||
|
@ -615,9 +617,6 @@ begin
|
|||
Result := TBigInt.Zero
|
||||
else
|
||||
Result := TBigInt.MultiplyAbsoluteValues(A, B, A.IsNegative <> B.IsNegative);
|
||||
//WriteLn(' a: ', A.ToString);
|
||||
//WriteLn(' b: ', B.ToString);
|
||||
//WriteLn('a*b op: ', Result.ToString);
|
||||
end;
|
||||
|
||||
operator shl(const A: TBigInt; const B: Integer): TBigInt;
|
||||
|
@ -627,51 +626,105 @@ var
|
|||
begin
|
||||
// Handles shift of zero.
|
||||
if A = 0 then
|
||||
Result := TBigInt.Zero
|
||||
else begin
|
||||
// Determines full digit shifts and bit shifts.
|
||||
DivMod(B, CBitsPerDigit, digitShifts, bitShifts);
|
||||
begin
|
||||
Result := TBigInt.Zero;
|
||||
Exit;
|
||||
end;
|
||||
|
||||
if bitShifts > 0 then
|
||||
// Determines full digit shifts and bit shifts.
|
||||
DivMod(B, CBitsPerDigit, digitShifts, bitShifts);
|
||||
|
||||
if bitShifts > 0 then
|
||||
begin
|
||||
reverseShift := CBitsPerDigit - bitShifts;
|
||||
len := Length(A.FDigits);
|
||||
lastDigit := A.FDigits[len - 1] >> reverseShift;
|
||||
newLength := len + digitShifts;
|
||||
|
||||
if lastDigit = 0 then
|
||||
SetLength(Result.FDigits, newLength)
|
||||
else
|
||||
SetLength(Result.FDigits, newLength + 1);
|
||||
|
||||
// Performs full digit shifts by shifting the access index j for A.FDigits.
|
||||
Result.FDigits[digitShifts] := A.FDigits[0] << bitShifts;
|
||||
j := 0;
|
||||
for i := digitShifts + 1 to newLength - 1 do
|
||||
begin
|
||||
reverseShift := CBitsPerDigit - bitShifts;
|
||||
len := Length(A.FDigits);
|
||||
lastDigit := A.FDigits[len - 1] >> reverseShift;
|
||||
newLength := len + digitShifts;
|
||||
|
||||
if lastDigit = 0 then
|
||||
SetLength(Result.FDigits, newLength)
|
||||
else
|
||||
SetLength(Result.FDigits, newLength + 1);
|
||||
|
||||
// Performs full digit shifts by shifting the access index j for A.FDigits.
|
||||
Result.FDigits[digitShifts] := A.FDigits[0] << bitShifts;
|
||||
j := 0;
|
||||
for i := digitShifts + 1 to newLength - 1 do
|
||||
begin
|
||||
// Performs bit shifts.
|
||||
Result.FDigits[i] := A.FDigits[j] >> reverseShift;
|
||||
Inc(j);
|
||||
Result.FDigits[i] := Result.FDigits[i] or (A.FDigits[j] << bitShifts);
|
||||
end;
|
||||
|
||||
if Length(Result.FDigits) > newLength then
|
||||
Result.FDigits[newLength] := lastDigit;
|
||||
end
|
||||
else begin
|
||||
// Performs full digit shifts by copy if there are no bit shifts.
|
||||
len := Length(A.FDigits);
|
||||
SetLength(Result.FDigits, len + digitShifts);
|
||||
for i := 0 to digitShifts - 1 do
|
||||
Result.FDigits[i] := 0;
|
||||
for i := 0 to len - 1 do
|
||||
Result.FDigits[i + digitShifts] := A.FDigits[i];
|
||||
// Performs bit shifts.
|
||||
Result.FDigits[i] := A.FDigits[j] >> reverseShift;
|
||||
Inc(j);
|
||||
Result.FDigits[i] := Result.FDigits[i] or (A.FDigits[j] << bitShifts);
|
||||
end;
|
||||
|
||||
Result.FIsNegative := A.IsNegative;
|
||||
if lastDigit > 0 then
|
||||
Result.FDigits[newLength] := lastDigit;
|
||||
end
|
||||
else begin
|
||||
// Performs full digit shifts by copy if there are no bit shifts.
|
||||
len := Length(A.FDigits);
|
||||
SetLength(Result.FDigits, len + digitShifts);
|
||||
for i := 0 to digitShifts - 1 do
|
||||
Result.FDigits[i] := 0;
|
||||
for i := 0 to len - 1 do
|
||||
Result.FDigits[i + digitShifts] := A.FDigits[i];
|
||||
end;
|
||||
//WriteLn(' a: ', A.ToString);
|
||||
//WriteLn('a<< op: ', Result.ToString);
|
||||
|
||||
Result.FIsNegative := A.IsNegative;
|
||||
end;
|
||||
|
||||
operator shr(const A: TBigInt; const B: Integer): TBigInt;
|
||||
var
|
||||
i, j, digitShifts, bitShifts, reverseShift, len, newLength: Integer;
|
||||
lastDigit: Cardinal;
|
||||
begin
|
||||
// Handles shift of zero.
|
||||
if A = 0 then
|
||||
begin
|
||||
Result := TBigInt.Zero;
|
||||
Exit;
|
||||
end;
|
||||
|
||||
// Determines full digit shifts and bit shifts.
|
||||
DivMod(B, CBitsPerDigit, digitShifts, bitShifts);
|
||||
|
||||
// Handles shift to zero.
|
||||
if digitShifts >= Length(A.FDigits) then
|
||||
begin
|
||||
Result := TBigInt.Zero;
|
||||
Exit;
|
||||
end;
|
||||
|
||||
if bitShifts > 0 then
|
||||
begin
|
||||
reverseShift := CBitsPerDigit - bitShifts;
|
||||
len := Length(A.FDigits);
|
||||
lastDigit := A.FDigits[len - 1] >> bitShifts;
|
||||
newLength := len - digitShifts;
|
||||
|
||||
if lastDigit = 0 then
|
||||
SetLength(Result.FDigits, newLength - 1)
|
||||
else
|
||||
SetLength(Result.FDigits, newLength);
|
||||
|
||||
// Performs full digit shifts by shifting the access index j for A.FDigits.
|
||||
j := digitShifts;
|
||||
for i := 0 to newLength - 2 do
|
||||
begin
|
||||
// Performs bit shifts.
|
||||
Result.FDigits[i] := A.FDigits[j] >> bitShifts;
|
||||
Inc(j);
|
||||
Result.FDigits[i] := Result.FDigits[i] or (A.FDigits[j] << reverseShift);
|
||||
end;
|
||||
|
||||
if lastDigit > 0 then
|
||||
Result.FDigits[newLength - 1] := lastDigit;
|
||||
end
|
||||
else
|
||||
// Performs full digit shifts by copy if there are no bit shifts.
|
||||
Result.FDigits := Copy(A.FDigits, digitShifts, Length(A.FDigits) - digitShifts);
|
||||
|
||||
Result.FIsNegative := A.IsNegative;
|
||||
end;
|
||||
|
||||
operator = (const A, B: TBigInt): Boolean;
|
||||
|
|
|
@ -55,7 +55,6 @@ type
|
|||
// TODO: TBigIntConversionTestCase
|
||||
// TODO: TBigIntIncrementDecrementTestCase
|
||||
// TODO: TBigIntQuotientTestCase
|
||||
// TODO: TBigIntShiftRightTestCase
|
||||
|
||||
{ TBigIntSignTestCase }
|
||||
|
||||
|
@ -210,6 +209,21 @@ type
|
|||
procedure TestZero;
|
||||
end;
|
||||
|
||||
{ TBigIntShiftRightTestCase }
|
||||
|
||||
TBigIntShiftRightTestCase = class(TTestCase)
|
||||
private
|
||||
procedure Test(const AHexValueOperand: string; const AShift: Integer; const AHexValueResult: string);
|
||||
published
|
||||
procedure TestShort;
|
||||
procedure TestShortWithCarry;
|
||||
procedure TestLongWithCarry;
|
||||
procedure TestLongWithMultiDigitCarry;
|
||||
procedure TestWithAlignedDigits;
|
||||
procedure TestShiftToZero;
|
||||
procedure TestZero;
|
||||
end;
|
||||
|
||||
{ TBigIntEqualityTestCase }
|
||||
|
||||
TBigIntEqualityTestCase = class(TTestCase)
|
||||
|
@ -718,7 +732,8 @@ end;
|
|||
|
||||
{ TBigIntShiftLeftTestCase }
|
||||
|
||||
procedure TBigIntShiftLeftTestCase.Test(const AHexValueOperand: string; const AShift: Integer; const AHexValueResult: string);
|
||||
procedure TBigIntShiftLeftTestCase.Test(const AHexValueOperand: string; const AShift: Integer; const AHexValueResult:
|
||||
string);
|
||||
var
|
||||
a, s: TBigInt;
|
||||
begin
|
||||
|
@ -767,6 +782,63 @@ begin
|
|||
Test('0', 119, '0');
|
||||
end;
|
||||
|
||||
{ TBigIntShiftRightTestCase }
|
||||
|
||||
procedure TBigIntShiftRightTestCase.Test(const AHexValueOperand: string; const AShift: Integer; const AHexValueResult:
|
||||
string);
|
||||
var
|
||||
a, s: TBigInt;
|
||||
begin
|
||||
a := TBigInt.FromHexadecimalString(AHexValueOperand);
|
||||
s := TBigInt.FromHexadecimalString(AHexValueResult);
|
||||
AssertTrue('BigInt from hexadecimal string ''' + AHexValueOperand + ''' shifted right by ''' + IntToStr(AShift)
|
||||
+ ''' was not equal to BigInt from hexadecimal string ''' + AHexValueResult + '''.',
|
||||
s = (a >> AShift));
|
||||
end;
|
||||
|
||||
procedure TBigIntShiftRightTestCase.TestShort;
|
||||
begin
|
||||
// BIN 100110101
|
||||
// BIN 10011
|
||||
Test('135', 4, '13');
|
||||
end;
|
||||
|
||||
procedure TBigIntShiftRightTestCase.TestShortWithCarry;
|
||||
begin
|
||||
// BIN 1 1101 1010 1110 1001 1000 0111 0000 0000 0000 1111
|
||||
// BIN 11 1011 0101 1101 0011 0000 1110
|
||||
Test('1DAE987000F', 15, '3B5D30E');
|
||||
end;
|
||||
|
||||
procedure TBigIntShiftRightTestCase.TestLongWithCarry;
|
||||
begin
|
||||
// BIN 10 0110 0001 0110 0100 0111 1100 1001 1001 1111 0010 1010 1000 1000 1010 0010 0010 1101 1101
|
||||
// BIN 100 1100 0010 1100 1000 1111 1001 0011 0011 1110 0101 0101 0001 0001 0100 0100
|
||||
Test('261647C99F2A88A22DD', 11, '4C2C8F933E551144');
|
||||
end;
|
||||
|
||||
procedure TBigIntShiftRightTestCase.TestLongWithMultiDigitCarry;
|
||||
begin
|
||||
Test('647C99F12A088A22FF6DD02187345A3B839401BFB9272', 104, '647C99F12A088A22FF6');
|
||||
end;
|
||||
|
||||
// Shifts the left operand by a multiple of the length of full TBigInt digits, so the digits will be shifted, but not
|
||||
// changed.
|
||||
procedure TBigIntShiftRightTestCase.TestWithAlignedDigits;
|
||||
begin
|
||||
Test('C5E10F0F39000AA2000C020000010000000000000F00000007', 32 * 5, 'C5E10F0F39');
|
||||
end;
|
||||
|
||||
procedure TBigIntShiftRightTestCase.TestShiftToZero;
|
||||
begin
|
||||
Test('B5D10F0F39882F', 150, '0');
|
||||
end;
|
||||
|
||||
procedure TBigIntShiftRightTestCase.TestZero;
|
||||
begin
|
||||
Test('0', 3, '0');
|
||||
end;
|
||||
|
||||
{ TBigIntEqualityTestCase }
|
||||
|
||||
procedure TBigIntEqualityTestCase.TestEqual(const AValue: Int64);
|
||||
|
@ -954,6 +1026,7 @@ initialization
|
|||
RegisterTest(TBigIntDifferenceTestCase);
|
||||
RegisterTest(TBigIntProductTestCase);
|
||||
RegisterTest(TBigIntShiftLeftTestCase);
|
||||
RegisterTest(TBigIntShiftRightTestCase);
|
||||
RegisterTest(TBigIntEqualityTestCase);
|
||||
RegisterTest(TBigIntComparisonTestCase);
|
||||
end.
|
||||
|
|
Loading…
Reference in New Issue