Added TBigInt.GetMostSignificantBitIndex and tests

This commit is contained in:
Stefan Müller 2024-05-20 15:03:54 +02:00
parent 2ca960f19c
commit 52cee73123
2 changed files with 76 additions and 0 deletions

View File

@ -76,6 +76,10 @@ type
property IsNegative: Boolean read FIsNegative; property IsNegative: Boolean read FIsNegative;
property Sign: Integer read GetSign; property Sign: Integer read GetSign;
class property Zero: TBigInt read GetZero; class property Zero: TBigInt read GetZero;
// 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.
function GetMostSignificantBitIndex: Int64;
function CompareTo(constref AOther: TBigInt): Integer; function CompareTo(constref AOther: TBigInt): Integer;
function TryToInt64(out AOutput: Int64): Boolean; function TryToInt64(out AOutput: Int64): Boolean;
// TODO: ToString is currently for debug output only. // TODO: ToString is currently for debug output only.
@ -461,6 +465,21 @@ begin
Result := StrToDWord(part); Result := StrToDWord(part);
end; end;
function TBigInt.GetMostSignificantBitIndex: Int64;
var
high, i: Integer;
begin
high := Length(FDigits) - 1;
if (high = 0) and (FDigits[0] = 0) then
Result := -1
else begin
i := CBitsPerDigit - 1;
while ((1 << i) and FDigits[high]) = 0 do
Dec(i);
Result := high * CBitsPerDigit + i;
end;
end;
function TBigInt.CompareTo(constref AOther: TBigInt): Integer; function TBigInt.CompareTo(constref AOther: TBigInt): Integer;
begin begin
if FIsNegative = AOther.FIsNegative then if FIsNegative = AOther.FIsNegative then
@ -549,6 +568,7 @@ end;
operator := (const A: Int64): TBigInt; operator := (const A: Int64): TBigInt;
begin begin
Result := TBigInt.FromInt64(A); Result := TBigInt.FromInt64(A);
//WriteLn(':=a op: ', Result.ToString);
end; end;
operator - (const A: TBigInt): TBigInt; operator - (const A: TBigInt): TBigInt;
@ -563,6 +583,8 @@ begin
end end
else else
Result := TBigInt.Zero; Result := TBigInt.Zero;
//WriteLn(' a: ', A.ToString);
//WriteLn('-a op: ', Result.ToString);
end; end;
operator + (const A, B: TBigInt): TBigInt; operator + (const A, B: TBigInt): TBigInt;
@ -571,6 +593,9 @@ begin
Result := TBigInt.AddAbsoluteValues(A, B, A.IsNegative) Result := TBigInt.AddAbsoluteValues(A, B, A.IsNegative)
else else
Result := TBigInt.SubtractAbsoluteValues(A, B, A.IsNegative); Result := TBigInt.SubtractAbsoluteValues(A, B, A.IsNegative);
//WriteLn(' a: ', A.ToString);
//WriteLn(' b: ', B.ToString);
//WriteLn('a+b op: ', Result.ToString);
end; end;
operator - (const A, B: TBigInt): TBigInt; operator - (const A, B: TBigInt): TBigInt;
@ -579,6 +604,9 @@ begin
Result := TBigInt.SubtractAbsoluteValues(A, B, A.IsNegative) Result := TBigInt.SubtractAbsoluteValues(A, B, A.IsNegative)
else else
Result := TBigInt.AddAbsoluteValues(A, B, A.IsNegative); Result := TBigInt.AddAbsoluteValues(A, B, A.IsNegative);
//WriteLn(' a: ', A.ToString);
//WriteLn(' b: ', B.ToString);
//WriteLn('a-b op: ', Result.ToString);
end; end;
operator * (const A, B: TBigInt): TBigInt; operator * (const A, B: TBigInt): TBigInt;
@ -587,6 +615,9 @@ begin
Result := TBigInt.Zero Result := TBigInt.Zero
else else
Result := TBigInt.MultiplyAbsoluteValues(A, B, A.IsNegative <> B.IsNegative); Result := TBigInt.MultiplyAbsoluteValues(A, B, A.IsNegative <> B.IsNegative);
//WriteLn(' a: ', A.ToString);
//WriteLn(' b: ', B.ToString);
//WriteLn('a*b op: ', Result.ToString);
end; end;
operator shl(const A: TBigInt; const B: Integer): TBigInt; operator shl(const A: TBigInt; const B: Integer): TBigInt;
@ -639,6 +670,8 @@ begin
Result.FIsNegative := A.IsNegative; Result.FIsNegative := A.IsNegative;
end; end;
//WriteLn(' a: ', A.ToString);
//WriteLn('a<< op: ', Result.ToString);
end; end;
operator = (const A, B: TBigInt): Boolean; operator = (const A, B: TBigInt): Boolean;

View File

@ -70,6 +70,17 @@ type
procedure TestLongNegative; procedure TestLongNegative;
end; end;
{ TBigIntMostSignificantBitIndexTestCase }
TBigIntMostSignificantBitIndexTestCase = class(TTestCase)
private
procedure Test(const ABinValue: string; const AExpectedIndex: Int64);
published
procedure TestZero;
procedure TestShort;
procedure TestLong;
end;
{ TBigIntFromInt64TestCase } { TBigIntFromInt64TestCase }
TBigIntFromInt64TestCase = class(TTestCase) TBigIntFromInt64TestCase = class(TTestCase)
@ -271,6 +282,37 @@ begin
Test('-192648F1305DD04757A24C873F29F60B6184B5', -1); Test('-192648F1305DD04757A24C873F29F60B6184B5', -1);
end; end;
{ TBigIntMostSignificantBitIndexTestCase }
procedure TBigIntMostSignificantBitIndexTestCase.Test(const ABinValue: string; const AExpectedIndex: Int64);
var
a: TBigInt;
begin
a := TBigInt.FromBinaryString(ABinValue);
AssertEquals('BigInt from binary string ''' + ABinValue + ''' did not have its most significant bit at index '''
+ IntToStr(AExpectedIndex) + '''.',
AExpectedIndex, a.GetMostSignificantBitIndex);
end;
procedure TBigIntMostSignificantBitIndexTestCase.TestZero;
begin
Test('0', -1);
end;
procedure TBigIntMostSignificantBitIndexTestCase.TestShort;
begin
Test('1', 0);
Test('11111101111001', 13);
Test('10010111101100001110110101111000', 31);
end;
procedure TBigIntMostSignificantBitIndexTestCase.TestLong;
begin
Test('111100010101010100011101010100011', 32);
Test('11101001101010111101000101010001010101010101111111001010101010010100101000101011111001000111001001100011', 103);
Test('111101100011110110111011010111100000000001010111101110101101101100101010110111101011010101001100', 95);
end;
{ TBigIntFromInt64TestCase } { TBigIntFromInt64TestCase }
procedure TBigIntFromInt64TestCase.Test(const AValue: Int64); procedure TBigIntFromInt64TestCase.Test(const AValue: Int64);
@ -903,6 +945,7 @@ end;
initialization initialization
RegisterTest(TBigIntSignTestCase); RegisterTest(TBigIntSignTestCase);
RegisterTest(TBigIntMostSignificantBitIndexTestCase);
RegisterTest(TBigIntFromInt64TestCase); RegisterTest(TBigIntFromInt64TestCase);
RegisterTest(TBigIntFromHexTestCase); RegisterTest(TBigIntFromHexTestCase);
RegisterTest(TBigIntFromBinTestCase); RegisterTest(TBigIntFromBinTestCase);