Browse Source

Optimized ToString(10) for large bitcounts

Ugochukwu Mmaduekwe 7 years ago
parent
commit
2b3b803525
1 changed files with 44 additions and 33 deletions
  1. 44 33
      CryptoLib/src/Math/ClpBigInteger.pas

+ 44 - 33
CryptoLib/src/Math/ClpBigInteger.pas

@@ -307,6 +307,10 @@ type
     class procedure AppendZeroExtendedString(var sl: TStringList;
     class procedure AppendZeroExtendedString(var sl: TStringList;
       const s: String; minLength: Int32); static; inline;
       const s: String; minLength: Int32); static; inline;
 
 
+    class procedure ToString(sl: TStringList; radix: Int32;
+      moduli: TList<TBigInteger>; scale: Int32; const pos: TBigInteger);
+      overload; static;
+
     class function CreateUValueOf(value: UInt64): TBigInteger; static;
     class function CreateUValueOf(value: UInt64): TBigInteger; static;
     class function CreateValueOf(value: Int64): TBigInteger; static;
     class function CreateValueOf(value: Int64): TBigInteger; static;
 
 
@@ -1176,6 +1180,33 @@ begin
   sl.Add(s);
   sl.Add(s);
 end;
 end;
 
 
+class procedure TBigInteger.ToString(sl: TStringList; radix: Int32;
+  moduli: TList<TBigInteger>; scale: Int32; const pos: TBigInteger);
+var
+  s: String;
+  qr: TCryptoLibGenericArray<TBigInteger>;
+begin
+  if (pos.BitLength < 64) then
+  begin
+    s := IntToStr(pos.Int64Value);
+    if ((sl.Count > 1) or ((sl.Count = 1) and (sl[0] <> '-'))) then
+    begin
+      AppendZeroExtendedString(sl, s, 1 shl scale);
+    end
+    else if (pos.SignValue <> 0) then
+    begin
+      sl.Append(s);
+    end;
+    Exit;
+  end;
+
+  System.Dec(scale);
+  qr := pos.DivideAndRemainder(moduli[scale]);
+
+  ToString(sl, radix, moduli, scale, qr[0]);
+  ToString(sl, radix, moduli, scale, qr[1]);
+end;
+
 class function TBigInteger.Arbitrary(sizeInBits: Int32): TBigInteger;
 class function TBigInteger.Arbitrary(sizeInBits: Int32): TBigInteger;
 begin
 begin
   Result := TBigInteger.Create(sizeInBits, RandomSource);
   Result := TBigInteger.Create(sizeInBits, RandomSource);
@@ -4144,12 +4175,11 @@ end;
 
 
 function TBigInteger.ToString(radix: Int32): String;
 function TBigInteger.ToString(radix: Int32): String;
 var
 var
-  firstNonZero, pos, mask, bits, i, exponent: Int32;
-  limit, power: Int64;
+  firstNonZero, pos, mask, bits, i, scale: Int32;
   sl: TStringList;
   sl: TStringList;
   s: TList<String>;
   s: TList<String>;
-  u, q, bigPower: TBigInteger;
-  qr: TCryptoLibGenericArray<TBigInteger>;
+  moduli: TList<TBigInteger>;
+  u, q, r: TBigInteger;
 begin
 begin
   // TODO Make this method work for other radices (ideally 2 <= radix <= 36 as in Java)
   // TODO Make this method work for other radices (ideally 2 <= radix <= 36 as in Java)
   case (radix) of
   case (radix) of
@@ -4271,41 +4301,22 @@ begin
             Exit;
             Exit;
           end;
           end;
 
 
-          // Based on algorithm 1a from chapter 4.4 in Seminumerical Algorithms (Knuth)
-
-          // Work out the largest power of 'rdx' that is a positive 64-bit integer
-          // TODO possibly cache power/exponent against radix?
-          limit := System.High(Int64) div radix;
-          power := radix;
-          exponent := 1;
-          while (power <= limit) do
-          begin
-            power := power * radix;
-            System.Inc(exponent);
-          end;
-
-          bigPower := TBigInteger.ValueOf(power);
-
-          s := TList<string>.Create();
+          // TODO Could cache the moduli for each radix (soft reference?)
+          moduli := TList<TBigInteger>.Create();
           try
           try
-            while (q.CompareTo(bigPower) >= 0) do
+            r := TBigInteger.ValueOf(radix);
+            while (r.CompareTo(q) <= 0) do
             begin
             begin
-              qr := q.DivideAndRemainder(bigPower);
-              s.Add(IntToStr(qr[1].Int64Value));
-              q := qr[0];
+              moduli.Add(r);
+              r := r.Square();
             end;
             end;
 
 
-            sl.Add(IntToStr(q.Int64Value));
-
-            i := s.Count - 1;
-            while i >= 0 do
-            begin
-              AppendZeroExtendedString(sl, s[i], exponent);
-              System.Dec(i);
-            end;
+            scale := moduli.Count;
+            sl.Capacity := sl.Capacity + (1 shl scale);
 
 
+            ToString(sl, radix, moduli, scale, q);
           finally
           finally
-            s.Free;
+            moduli.Free;
           end;
           end;
 
 
         end;
         end;