]> gitweb.factorcode.org Git - factor.git/blobdiff - vm/bignum.cpp
help.html: making search box have first tab index
[factor.git] / vm / bignum.cpp
index c8dd5eed021dc0367b5294503bd6d0b81594a33b..ed1bbfaa6220075c9aab2a163e8fcdbf9669d1b2 100644 (file)
@@ -62,17 +62,17 @@ int factor_vm::bignum_equal_p(bignum* x, bignum* y) {
 }
 
 enum bignum_comparison factor_vm::bignum_compare(bignum* x, bignum* y) {
-  return ((BIGNUM_ZERO_P(x)) ? ((BIGNUM_ZERO_P(y)) ? bignum_comparison_equal
+  return ((BIGNUM_ZERO_P(x)) ? ((BIGNUM_ZERO_P(y)) ? BIGNUM_COMPARISON_EQUAL
                                                    : (BIGNUM_NEGATIVE_P(y))
-                                    ? bignum_comparison_greater
-                                    : bignum_comparison_less)
+                                    ? BIGNUM_COMPARISON_GREATER
+                                    : BIGNUM_COMPARISON_LESS)
                              : (BIGNUM_ZERO_P(y))
-              ? ((BIGNUM_NEGATIVE_P(x)) ? bignum_comparison_less
-                                        : bignum_comparison_greater)
+              ? ((BIGNUM_NEGATIVE_P(x)) ? BIGNUM_COMPARISON_LESS
+                                        : BIGNUM_COMPARISON_GREATER)
               : (BIGNUM_NEGATIVE_P(x))
               ? ((BIGNUM_NEGATIVE_P(y)) ? (bignum_compare_unsigned(y, x))
-                                        : (bignum_comparison_less))
-              : ((BIGNUM_NEGATIVE_P(y)) ? (bignum_comparison_greater)
+                                        : (BIGNUM_COMPARISON_LESS))
+              : ((BIGNUM_NEGATIVE_P(y)) ? (BIGNUM_COMPARISON_GREATER)
                                         : (bignum_compare_unsigned(x, y))));
 }
 
@@ -203,17 +203,17 @@ void factor_vm::bignum_divide(bignum* numerator, bignum* denominator,
     int q_negative_p =
         ((BIGNUM_NEGATIVE_P(denominator)) ? (!r_negative_p) : r_negative_p);
     switch (bignum_compare_unsigned(numerator, denominator)) {
-      case bignum_comparison_equal: {
+      case BIGNUM_COMPARISON_EQUAL: {
         (*quotient) = (BIGNUM_ONE(q_negative_p));
         (*remainder) = (BIGNUM_ZERO());
         break;
       }
-      case bignum_comparison_less: {
+      case BIGNUM_COMPARISON_LESS: {
         (*quotient) = (BIGNUM_ZERO());
         (*remainder) = numerator;
         break;
       }
-      case bignum_comparison_greater: {
+      case BIGNUM_COMPARISON_GREATER: {
         if ((BIGNUM_LENGTH(denominator)) == 1) {
           bignum_digit_type digit = (BIGNUM_REF(denominator, 0));
           if (digit == 1) {
@@ -254,11 +254,11 @@ bignum* factor_vm::bignum_quotient(bignum* numerator, bignum* denominator) {
         ((BIGNUM_NEGATIVE_P(denominator)) ? (!(BIGNUM_NEGATIVE_P(numerator)))
                                           : (BIGNUM_NEGATIVE_P(numerator)));
     switch (bignum_compare_unsigned(numerator, denominator)) {
-      case bignum_comparison_equal:
+      case BIGNUM_COMPARISON_EQUAL:
         return (BIGNUM_ONE(q_negative_p));
-      case bignum_comparison_less:
+      case BIGNUM_COMPARISON_LESS:
         return (BIGNUM_ZERO());
-      case bignum_comparison_greater:
+      case BIGNUM_COMPARISON_GREATER:
       default: // to appease gcc -Wall
                {
         bignum* quotient;
@@ -291,11 +291,11 @@ bignum* factor_vm::bignum_remainder(bignum* numerator, bignum* denominator) {
   if (BIGNUM_ZERO_P(numerator))
     return numerator;
   switch (bignum_compare_unsigned(numerator, denominator)) {
-    case bignum_comparison_equal:
+    case BIGNUM_COMPARISON_EQUAL:
       return (BIGNUM_ZERO());
-    case bignum_comparison_less:
+    case BIGNUM_COMPARISON_LESS:
       return numerator;
-    case bignum_comparison_greater:
+    case BIGNUM_COMPARISON_GREATER:
     default: // to appease gcc -Wall
              {
       bignum* remainder;
@@ -321,7 +321,7 @@ bignum* factor_vm::bignum_remainder(bignum* numerator, bignum* denominator) {
 // cell_to_bignum, fixnum_to_bignum, long_long_to_bignum, ulong_long_to_bignum
 
 // Allocates memory
-#define FOO_TO_BIGNUM(name, type, stype, utype)                       \
+#define FOO_TO_BIGNUM_SIGNED(name, type, utype)                       \
   bignum* factor_vm::name##_to_bignum(type n) {                       \
     int negative_p;                                                   \
     /* Special cases win when these small constants are cached. */    \
@@ -329,11 +329,11 @@ bignum* factor_vm::bignum_remainder(bignum* numerator, bignum* denominator) {
       return (BIGNUM_ZERO());                                         \
     if (n == 1)                                                       \
       return (BIGNUM_ONE(0));                                         \
-    if (n < (type) 0 && n == (type) - 1)                              \
+    if (n < (type) 0 && n == (type) -1)                               \
       return (BIGNUM_ONE(1));                                         \
     {                                                                 \
       utype accumulator =                                             \
-          ((negative_p = (n < (type) 0)) ? ((type)(-(stype) n)) : n); \
+          ((negative_p = n < (type) 0) ? -n : n);                     \
       if (accumulator < BIGNUM_RADIX)                                 \
       {                                                               \
         bignum* result = allot_bignum(1, negative_p);                 \
@@ -358,10 +358,44 @@ bignum* factor_vm::bignum_remainder(bignum* numerator, bignum* denominator) {
     }                                                                 \
   }
 
-FOO_TO_BIGNUM(cell, cell, fixnum, cell)
-FOO_TO_BIGNUM(fixnum, fixnum, fixnum, cell)
-FOO_TO_BIGNUM(long_long, int64_t, int64_t, uint64_t)
-FOO_TO_BIGNUM(ulong_long, uint64_t, int64_t, uint64_t)
+// Allocates memory
+#define FOO_TO_BIGNUM_UNSIGNED(name, type, utype)                     \
+  bignum* factor_vm::name##_to_bignum(type n) {                       \
+    /* Special cases win when these small constants are cached. */    \
+    if (n == 0)                                                       \
+      return (BIGNUM_ZERO());                                         \
+    if (n == 1)                                                       \
+      return (BIGNUM_ONE(0));                                         \
+    {                                                                 \
+      utype accumulator = n;                                          \
+      if (accumulator < BIGNUM_RADIX)                                 \
+      {                                                               \
+        bignum* result = allot_bignum(1, false);                      \
+        bignum_digit_type* scan = (BIGNUM_START_PTR(result));         \
+        *scan = (accumulator & BIGNUM_DIGIT_MASK);                    \
+        return (result);                                              \
+      } else {                                                        \
+        bignum_digit_type result_digits[BIGNUM_DIGITS_FOR(type)];     \
+        bignum_digit_type* end_digits = result_digits;                \
+        do {                                                          \
+          (*end_digits++) = (accumulator & BIGNUM_DIGIT_MASK);        \
+          accumulator >>= BIGNUM_DIGIT_LENGTH;                        \
+        } while (accumulator != 0);                                   \
+        bignum* result =                                              \
+           (allot_bignum((end_digits - result_digits), false));       \
+        bignum_digit_type* scan_digits = result_digits;               \
+        bignum_digit_type* scan_result = (BIGNUM_START_PTR(result));  \
+        while (scan_digits < end_digits)                              \
+          (*scan_result++) = (*scan_digits++);                        \
+        return (result);                                              \
+      }                                                               \
+    }                                                                 \
+  }
+
+FOO_TO_BIGNUM_SIGNED(fixnum, fixnum, cell)
+FOO_TO_BIGNUM_UNSIGNED(cell, cell, cell)
+FOO_TO_BIGNUM_SIGNED(long_long, int64_t, uint64_t)
+FOO_TO_BIGNUM_UNSIGNED(ulong_long, uint64_t, uint64_t)
 
 // cannot allocate memory
 // bignum_to_cell, fixnum_to_cell, long_long_to_cell, ulong_long_to_cell
@@ -480,9 +514,9 @@ enum bignum_comparison factor_vm::bignum_compare_unsigned(bignum* x,
   bignum_length_type x_length = (BIGNUM_LENGTH(x));
   bignum_length_type y_length = (BIGNUM_LENGTH(y));
   if (x_length < y_length)
-    return (bignum_comparison_less);
+    return BIGNUM_COMPARISON_LESS;
   if (x_length > y_length)
-    return (bignum_comparison_greater);
+    return BIGNUM_COMPARISON_GREATER;
   {
     bignum_digit_type* start_x = (BIGNUM_START_PTR(x));
     bignum_digit_type* scan_x = (start_x + x_length);
@@ -491,12 +525,12 @@ enum bignum_comparison factor_vm::bignum_compare_unsigned(bignum* x,
       bignum_digit_type digit_x = (*--scan_x);
       bignum_digit_type digit_y = (*--scan_y);
       if (digit_x < digit_y)
-        return (bignum_comparison_less);
+        return BIGNUM_COMPARISON_LESS;
       if (digit_x > digit_y)
-        return (bignum_comparison_greater);
+        return BIGNUM_COMPARISON_GREATER;
     }
   }
-  return (bignum_comparison_equal);
+  return BIGNUM_COMPARISON_EQUAL;
 }
 
 // Addition
@@ -565,13 +599,13 @@ bignum* factor_vm::bignum_subtract_unsigned(bignum* x_, bignum* y_) {
 
   int negative_p = 0;
   switch (bignum_compare_unsigned(x.untagged(), y.untagged())) {
-    case bignum_comparison_equal:
+    case BIGNUM_COMPARISON_EQUAL:
       return (BIGNUM_ZERO());
-    case bignum_comparison_less:
+    case BIGNUM_COMPARISON_LESS:
       swap(x, y);
       negative_p = 1;
       break;
-    case bignum_comparison_greater:
+    case BIGNUM_COMPARISON_GREATER:
       negative_p = 0;
       break;
   }
@@ -797,7 +831,7 @@ void factor_vm::bignum_divide_unsigned_large_denominator(
         bignum_destructive_unnormalization(u.untagged(), shift);
     }
 
-    q = bignum_trim(q.untagged());
+    q.set_untagged(bignum_trim(q.untagged()));
     *quotient = q.untagged();
   } else {
 
@@ -821,7 +855,7 @@ void factor_vm::bignum_divide_unsigned_large_denominator(
       }
   }
 
-  u = bignum_trim(u.untagged());
+  u.set_untagged(bignum_trim(u.untagged()));
   if (remainder != NULL)
     *remainder = u.untagged();
 }
@@ -996,7 +1030,7 @@ void factor_vm::bignum_divide_unsigned_medium_denominator(
       (*scan) = qj;
     }
 
-    q = bignum_trim(q.untagged());
+    q.set_untagged(bignum_trim(q.untagged()));
 
     if (remainder != ((bignum**)0)) {
       if (shift != 0)
@@ -1179,7 +1213,7 @@ void factor_vm::bignum_divide_unsigned_small_denominator(
 
   bignum_digit_type r = bignum_destructive_scale_down(q.untagged(), denominator);
 
-  q = bignum_trim(q.untagged());
+  q.set_untagged(bignum_trim(q.untagged()));
 
   if (remainder != ((bignum**)0))
     (*remainder) = bignum_digit_to_bignum(r, r_negative_p);
@@ -1703,7 +1737,7 @@ bignum* factor_vm::bignum_gcd(bignum* a_, bignum* b_) {
   data_root<bignum> ac(bignum_maybe_new_sign(a.untagged(), 0), this);
   data_root<bignum> bc(bignum_maybe_new_sign(b.untagged(), 0), this);
 
-  if (bignum_compare(ac.untagged(), bc.untagged()) == bignum_comparison_less) {
+  if (bignum_compare(ac.untagged(), bc.untagged()) == BIGNUM_COMPARISON_LESS) {
     swap(ac, bc);
   }
 
@@ -1723,7 +1757,8 @@ bignum* factor_vm::bignum_gcd(bignum* a_, bignum* b_) {
   data_root<bignum> a(a_, this);
   data_root<bignum> b(b_, this);
   bignum_twodigit_type x, y, q, s, t, A, B, C, D;
-  int nbits, k;
+  unsigned long nbits;
+  int k;
   bignum_length_type size_a, size_b, size_c;
   bignum_digit_type* scan_a, *scan_b, *scan_c, *scan_d;
   bignum_digit_type* a_end, *b_end, *c_end;
@@ -1748,7 +1783,7 @@ bignum* factor_vm::bignum_gcd(bignum* a_, bignum* b_) {
   b = d;
 
   // Initial reduction: make sure that 0 <= b <= a.
-  if (bignum_compare(a.untagged(), b.untagged()) == bignum_comparison_less) {
+  if (bignum_compare(a.untagged(), b.untagged()) == BIGNUM_COMPARISON_LESS) {
     swap(a, b);
     std::swap(size_a, size_b);
   }
@@ -1797,7 +1832,7 @@ bignum* factor_vm::bignum_gcd(bignum* a_, bignum* b_) {
       }
       data_root<bignum> e(bignum_trim(a.untagged()), this);
       data_root<bignum> f(bignum_trim(b.untagged()), this);
-      c = bignum_remainder(e.untagged(), f.untagged());
+      c.set_untagged(bignum_remainder(e.untagged(), f.untagged()));
       if (c.untagged() == BIGNUM_OUT_OF_BAND) {
         return c.untagged();
       }