浏览代码

Making shift10 work in both directions.
Precondition is that if places is less than zero, there are enough digits to support that transform.
TODO: add checks

Samuel Jaffe 8 年之前
父节点
当前提交
5173ebab09
共有 2 个文件被更改,包括 22 次插入13 次删除
  1. 1 0
      include/bignum_helper.h
  2. 21 13
      src/bignum_helper.cpp

+ 1 - 0
include/bignum_helper.h

@@ -17,4 +17,5 @@ namespace math { namespace detail {
   void subtract_nounderflow(data_type & rhs, data_type const & lhs, size_t offset = 0);
   void multiply(data_type & rhs, data_type const & lhs);
   data_type divide(data_type & remainder, data_type const & divisor);
+  data_type shift10(data_type const & data, int32_t places);
 } }

+ 21 - 13
src/bignum_helper.cpp

@@ -82,10 +82,10 @@ namespace math { namespace detail {
       for (size_t j = lbnd; j > 0; --j) {
         // Max input              999,999,999
         // Max output 999,999,998,000,000,001
-        int64_t product = static_cast<int64_t>(value) * static_cast<int64_t>(lhs[j-1]);
+        int64_t product = int64_t(value) * lhs[j-1];
         int64_t overflow = product / OVER_SEG;
-        rhs[i+j-2] += static_cast<int32_t>(product - (overflow * OVER_SEG));
-        rhs[i+j-1] += static_cast<int32_t>(overflow);
+        rhs[i+j-2] += int32_t(product - (overflow * OVER_SEG));
+        rhs[i+j-1] += int32_t(overflow);
       }
       rhs[i-1] -= value;
     }
@@ -100,29 +100,37 @@ namespace math { namespace detail {
     while (rhs.back() == 0) { rhs.pop_back(); }
   }
   
-  data_type shift10(data_type const & data, int32_t pow, size_t shift) {
+  int32_t powers[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000 };
+  
+  data_type shift10(data_type const & data, int32_t places) {
+    int32_t shift = places / SEG_DIGITS;
+    if (places < 0) { --shift; }
+    int64_t const pow = powers[places - (shift * SEG_DIGITS)];
     size_t const bnd = data.size();
-    data_type rval(bnd + shift + 1);
-    for (size_t i = 0; i < bnd; ++i) {
-      int64_t product = static_cast<int64_t>(data[i]) * static_cast<int64_t>(pow);
+    data_type rval(size_t((int32_t)bnd + shift) + 1);
+    for (size_t i = 0, o = size_t(std::max(0, shift));
+         i < bnd; ++i, ++o) {
+      int64_t product = int64_t(data[i]) * pow;
       int64_t overflow = product / OVER_SEG;
-      rval[i+shift] += static_cast<int32_t>(product - (overflow * OVER_SEG));
-      rval[i+shift+1] += static_cast<int32_t>(overflow);
+      rval[o] += int32_t(product - (overflow * OVER_SEG));
+      rval[o+1] += int32_t(overflow);
+    }
+    if (shift < 0) {
+      // TODO rounding
+      rval.erase(rval.begin(), rval.begin()-shift);
     }
     if (rval.back() == 0 && rval.size() > 1) { rval.pop_back(); }
     return rval;
   }
   
   size_t digits(int32_t val) {
-    return val == 0 ? 1 : static_cast<size_t>(floor(log10(val))) + 1;
+    return val == 0 ? 1 : size_t(floor(log10(val))) + 1;
   }
   
   size_t digits(data_type const & data) {
     return SEG_DIGITS * (data.size()-1) + digits(data.back());
   }
   
-  int32_t powers[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000 };
-  
   data_type divide(data_type & remainder, data_type const & divisor) {
     data_type accum{0};
     auto const dig = digits(divisor);
@@ -130,7 +138,7 @@ namespace math { namespace detail {
       auto const diff = std::max(1UL, digits(remainder) - dig) - 1;
       auto const shift = diff / SEG_DIGITS;
       auto const ipow = diff - (shift * SEG_DIGITS);
-      data_type value{shift10(divisor, powers[ipow], 0)};
+      data_type value{shift10(divisor, int32_t(ipow))};
       do {
         subtract_nounderflow(remainder, value, shift);
         add(accum, powers[ipow], shift);