]> www.ginac.de Git - cln.git/commitdiff
* src/integer/conv/cl_I_from_digits.cc (digits_to_I): Speedup when
authorRichard Kreckel <kreckel@ginac.de>
Tue, 12 Oct 2004 20:24:40 +0000 (20:24 +0000)
committerRichard Kreckel <kreckel@ginac.de>
Tue, 12 Oct 2004 20:24:40 +0000 (20:24 +0000)
the base is a power of two.

ChangeLog
src/integer/conv/cl_I_from_digits.cc

index 5b26f1879b72a9472851b00a411e06661cefabaf..3a716c7ba534a2fa97df004b14e957e17059ef43 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2004-10-12  Richard B. Kreckel  <kreckel@ginac.de>
+
+       * src/integer/conv/cl_I_from_digits.cc (digits_to_I): Speedup when
+       the base is a power of two.
+
 2004-10-05  Richard B. Kreckel  <kreckel@ginac.de>
 
        * src/integer/conv/cl_I_to_digits.cc (I_to_digits): Fix bug in base 32.
index 5fc3426d56f8dacc74781b4e80fdb7198a59762b..76296aae93e41a49d90c256d3bb94b592887aa06 100644 (file)
-// digits_to_I().
-
-// General includes.
-#include "cl_sysdep.h"
-
-// Specification.
-#include "cl_I.h"
-
-
-// Implementation.
-
-#include "cl_DS.h"
-
-namespace cln {
-
-const cl_I digits_to_I (const char * MSBptr, uintL len, uintD base)
-{
-      CL_ALLOCA_STACK;
-      var uintD* erg_MSDptr;
-      var uintC erg_len;
-      var uintD* erg_LSDptr;
-      // Platz fürs Ergebnis:
-      // 1+ceiling(len*log(base)/(intDsize*log(2))) oder etwas mehr Digits
-      var uintL need = 1+floor(len,intDsize*256); // > len/(intDsize*256) >=0
-      switch (base) // need mit ceiling(256*log(base)/log(2)) multiplizieren:
-        { case 2: need = 256*need; break;
-          case 3: need = 406*need; break;
-          case 4: need = 512*need; break;
-          case 5: need = 595*need; break;
-          case 6: need = 662*need; break;
-          case 7: need = 719*need; break;
-          case 8: need = 768*need; break;
-          case 9: need = 812*need; break;
-          case 10: need = 851*need; break;
-          case 11: need = 886*need; break;
-          case 12: need = 918*need; break;
-          case 13: need = 948*need; break;
-          case 14: need = 975*need; break;
-          case 15: need = 1001*need; break;
-          case 16: need = 1024*need; break;
-          case 17: need = 1047*need; break;
-          case 18: need = 1068*need; break;
-          case 19: need = 1088*need; break;
-          case 20: need = 1107*need; break;
-          case 21: need = 1125*need; break;
-          case 22: need = 1142*need; break;
-          case 23: need = 1159*need; break;
-          case 24: need = 1174*need; break;
-          case 25: need = 1189*need; break;
-          case 26: need = 1204*need; break;
-          case 27: need = 1218*need; break;
-          case 28: need = 1231*need; break;
-          case 29: need = 1244*need; break;
-          case 30: need = 1257*need; break;
-          case 31: need = 1269*need; break;
-          case 32: need = 1280*need; break;
-          case 33: need = 1292*need; break;
-          case 34: need = 1303*need; break;
-          case 35: need = 1314*need; break;
-          case 36: need = 1324*need; break;
-          default: NOTREACHED
-        }
-      // Nun gilt need >= len*log(base)/(intDsize*log(2)).
-      need += 1;
-      num_stack_alloc(need,,erg_LSDptr=);
-      erg_MSDptr = erg_LSDptr; erg_len = 0;
-      // Ziffern einzeln draufaddieren:
-      while (len > 0)
-        { // erg_MSDptr/erg_len/erg_LSDptr ist eine NUDS, erg_len < need.
-          var uintB ch = *(const uintB *)MSBptr; MSBptr++; // nächstes Character
-          if (!(ch=='.')) // Punkt überlesen
-            { // Wert von ch ('0'-'9','A'-'Z','a'-'z') bilden:
-              ch = ch - '0';
-              if (ch > '9'-'0') // keine Ziffer?
-                { ch = ch+'0'-'A'+10;
-                  if (ch > 'Z'-'A'+10) // kein Großbuchstabe?
-                    { ch = ch+'A'-'a'; } // dann ein Kleinbuchstabe
-                }
-              // multipliziere erg mit base und addiere ch:
-             {var uintD carry = mulusmall_loop_lsp(base,erg_LSDptr,erg_len,ch);
-              if (!(carry==0))
-                // muß NUDS vergrößern:
-                { lsprefnext(erg_MSDptr) = carry; erg_len++; }
-            }}
-          len--;
-        }
-      return NUDS_to_I(erg_MSDptr,erg_len);
-}
-
-}  // namespace cln
+// digits_to_I().\r
+\r
+// General includes.\r
+#include "cl_sysdep.h"\r
+\r
+// Specification.\r
+#include "cl_I.h"\r
+\r
+\r
+// Implementation.\r
+\r
+#include "cl_DS.h"\r
+\r
+namespace cln {\r
+\r
+const cl_I digits_to_I (const char * MSBptr, uintL len, uintD base)\r
+{\r
+      CL_ALLOCA_STACK;\r
+      var uintD* erg_MSDptr;\r
+      var uintC erg_len;\r
+      var uintD* erg_LSDptr;\r
+      if ((base & (base-1)) == 0) {\r
+        // Fast path for powers of two: write the digits from least\r
+        // significant to most significant into the result NUDS.\r
+        var int b = (base==2 ? 1 : base==4 ? 2 : base==8 ? 3 : base==16 ? 4 : /*base==32*/ 5);\r
+        num_stack_alloc(1+(len*b-1)/intDsize,,erg_LSDptr=);\r
+        erg_MSDptr = erg_LSDptr; erg_len = 0;\r
+        var uintD d = 0;  // resulting digit\r
+        var int ch_where = 0;  // position of ch inside d\r
+        while (len > 0)\r
+          { var uintB ch = *(const uintB *)(MSBptr+len-1); // next character\r
+            if (!(ch=='.')) // skip decimal point\r
+              { // Compute value of ch ('0'-'9','A'-'Z','a'-'z'):\r
+                ch = ch - '0';\r
+                if (ch > '9'-'0') // not a digit?\r
+                  { ch = ch+'0'-'A'+10;\r
+                    if (ch > 'Z'-'A'+10) // not an uppercase letter?\r
+                      { ch = ch+'A'-'a'; } // must be lowercase!\r
+                  }\r
+                d = d | (uintD)ch<<ch_where;\r
+                ch_where = ch_where+b;\r
+                if (ch_where >= intDsize) {\r
+                  // d is ready to be written into the NUDS:\r
+                  lsprefnext(erg_MSDptr) = d;\r
+                  ch_where = ch_where-intDsize;\r
+                  d = (uintD)ch >> b-ch_where;  // carry\r
+                  erg_len++;\r
+                }\r
+              }\r
+            len--;\r
+          }\r
+        if (d != 0) {  // is there anything left over?\r
+          lsprefnext(erg_MSDptr) = d;\r
+          ++erg_len;\r
+        }\r
+      } else {\r
+        // Slow path: Add digits one by one for non-powers of two.\r
+        // Platz fürs Ergebnis:\r
+        // 1+ceiling(len*log(base)/(intDsize*log(2))) or some more digits\r
+        var uintL need = 1+floor(len,intDsize*256); // > len/(intDsize*256) >=0\r
+        switch (base) // multiply need with ceiling(256*log(base)/log(2)):\r
+          {\r
+          //case 2: need = 256*need; break;\r
+            case 3: need = 406*need; break;\r
+          //case 4: need = 512*need; break;\r
+            case 5: need = 595*need; break;\r
+            case 6: need = 662*need; break;\r
+            case 7: need = 719*need; break;\r
+          //case 8: need = 768*need; break;\r
+            case 9: need = 812*need; break;\r
+            case 10: need = 851*need; break;\r
+            case 11: need = 886*need; break;\r
+            case 12: need = 918*need; break;\r
+            case 13: need = 948*need; break;\r
+            case 14: need = 975*need; break;\r
+            case 15: need = 1001*need; break;\r
+          //case 16: need = 1024*need; break;\r
+            case 17: need = 1047*need; break;\r
+            case 18: need = 1068*need; break;\r
+            case 19: need = 1088*need; break;\r
+            case 20: need = 1107*need; break;\r
+            case 21: need = 1125*need; break;\r
+            case 22: need = 1142*need; break;\r
+            case 23: need = 1159*need; break;\r
+            case 24: need = 1174*need; break;\r
+            case 25: need = 1189*need; break;\r
+            case 26: need = 1204*need; break;\r
+            case 27: need = 1218*need; break;\r
+            case 28: need = 1231*need; break;\r
+            case 29: need = 1244*need; break;\r
+            case 30: need = 1257*need; break;\r
+            case 31: need = 1269*need; break;\r
+          //case 32: need = 1280*need; break;\r
+            case 33: need = 1292*need; break;\r
+            case 34: need = 1303*need; break;\r
+            case 35: need = 1314*need; break;\r
+            case 36: need = 1324*need; break;\r
+            default: NOTREACHED\r
+          }\r
+        // Now we have need >= len*log(base)/(intDsize*log(2)).\r
+        need += 1;\r
+        // Add digits one by one:\r
+        num_stack_alloc(need,,erg_LSDptr=);\r
+        erg_MSDptr = erg_LSDptr; erg_len = 0;\r
+        while (len > 0)\r
+          { // erg_MSDptr/erg_len/erg_LSDptr is a NUDS, erg_len < need.\r
+            var uintB ch = *(const uintB *)MSBptr; MSBptr++; // next character\r
+            if (!(ch=='.')) // skip decimal point\r
+              { // Compute value of ('0'-'9','A'-'Z','a'-'z'):\r
+                ch = ch - '0';\r
+                if (ch > '9'-'0') // not a digit?\r
+                  { ch = ch+'0'-'A'+10;\r
+                    if (ch > 'Z'-'A'+10) // not an uppercase letter?\r
+                      { ch = ch+'A'-'a'; } // must be lowercase!\r
+                  }\r
+                // multiply erg with base and add ch:\r
+               {var uintD carry = mulusmall_loop_lsp(base,erg_LSDptr,erg_len,ch);\r
+                if (!(carry==0))\r
+                  // need to extend NUDS:\r
+                  { lsprefnext(erg_MSDptr) = carry; erg_len++; }\r
+              }}\r
+            len--;\r
+          }\r
+      }\r
+      return NUDS_to_I(erg_MSDptr,erg_len);\r
+}\r
+\r
+}  // namespace cln\r