Browse Source

Reducing code duplication in biginteger.
Fixing bug in detail::compare with offsets

Samuel Jaffe 8 years ago
parent
commit
4f9108a734
4 changed files with 32 additions and 37 deletions
  1. 1 0
      include/biginteger.h
  2. 1 0
      include/bignum_helper.h
  3. 27 32
      src/biginteger.cpp
  4. 3 5
      src/bignum_helper.cpp

+ 1 - 0
include/biginteger.h

@@ -59,6 +59,7 @@ namespace math {
     friend bool operator> (biginteger const &, biginteger const &);
   private:
     biginteger(bool, uint64_t);
+    void subtract_impl(biginteger const & lhs, bool is_sub);
     friend void swap(biginteger & rhs, biginteger & lhs) {
       using std::swap;
       swap(rhs.is_negative, lhs.is_negative);

+ 1 - 0
include/bignum_helper.h

@@ -11,6 +11,7 @@
 
 namespace math { namespace detail {
   using data_type = std::vector<int32_t>;
+  constexpr const int32_t powers[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000 };
   // 1 => GREATER, 0 => EQUAL, -1 => LESS
   int compare(data_type const & rhs, data_type const & lhs, size_t offset = 0);
   void add(data_type & rhs, data_type const & lhs, size_t offset = 0);

+ 27 - 32
src/biginteger.cpp

@@ -14,6 +14,13 @@
 
 using namespace math;
 
+static void read(int32_t & dst, char const * & str, size_t len) {
+  char seg[biginteger::SEG_DIGITS+1] = "";
+  strncpy(seg, str, len);
+  dst = atoi(seg);
+  str += len;
+}
+
 biginteger::biginteger()
 : biginteger(false, 0) {}
 
@@ -23,19 +30,11 @@ biginteger::biginteger(char const * number)
   auto len = strlen(number);
   auto elems = len/SEG_DIGITS;
   data.resize(elems);
-  {
-    auto small = len-(elems*SEG_DIGITS);
-    if (small > 0) {
-      char seg[SEG_DIGITS+1] = "";
-      strncpy(seg, number, small);
-      data.push_back(atoi(seg));
-      number += small;
-    }
+  if (auto small = len-(elems*SEG_DIGITS)) {
+    read(*data.insert(data.end(), 0), number, small);
   }
-  for (data_type::size_type idx = elems; idx > 0; --idx, number += SEG_DIGITS) {
-    char seg[SEG_DIGITS+1] = "";
-    strncpy(seg, number, SEG_DIGITS);
-    data[idx-1] = atoi(seg);
+  for (data_type::size_type idx = elems; idx > 0; --idx) {
+    read(data[idx-1], number, SEG_DIGITS);
   }
 }
 
@@ -48,22 +47,27 @@ is_negative(neg) {
   } while ((value = next) > 0);
 }
 
+void biginteger::subtract_impl(biginteger const & lhs, bool is_sub) {
+  auto cmp = detail::compare(data, lhs.data);
+  if (cmp == 0) {
+    *this = biginteger::ZERO;
+  } else if (cmp > 0) {
+    detail::subtract_nounderflow(data, lhs.data);
+  } else {
+    data_type tmp{lhs.data};
+    is_negative = lhs.is_negative ^ is_sub;
+    swap(data, tmp);
+    detail::subtract_nounderflow(data, tmp);
+  }
+}
+
 biginteger & math::operator+=(biginteger & rhs, biginteger const & lhs) {
   if (lhs == biginteger::ZERO) { return rhs; }
   else if (rhs == biginteger::ZERO) { rhs=lhs; }
   else if (rhs.is_negative == lhs.is_negative) {
     detail::add(rhs.data, lhs.data);
   } else {
-    auto cmp = detail::compare(rhs.data, lhs.data);
-    if (cmp == 0) {
-      rhs = biginteger::ZERO;
-    } else if (cmp > 0) {
-      detail::subtract_nounderflow(rhs.data, lhs.data);
-    } else {
-      biginteger tmp{lhs};
-      swap(rhs, tmp);
-      detail::subtract_nounderflow(rhs.data, tmp.data);
-    }
+    rhs.subtract_impl(lhs, false);
   }
   return rhs;
 }
@@ -74,16 +78,7 @@ biginteger & math::operator-=(biginteger & rhs, biginteger const & lhs) {
   if (rhs.is_negative != lhs.is_negative) {
     detail::add(rhs.data, lhs.data);
   } else {
-    auto cmp = detail::compare(rhs.data, lhs.data);
-    if (cmp == 0) {
-      rhs = biginteger::ZERO;
-    } else if (cmp > 0) {
-      detail::subtract_nounderflow(rhs.data, lhs.data);
-    } else {
-      biginteger tmp{-lhs};
-      swap(rhs, tmp);
-      detail::subtract_nounderflow(rhs.data, tmp.data);;
-    }
+    rhs.subtract_impl(lhs, true);
   }
   return rhs;
 }

+ 3 - 5
src/bignum_helper.cpp

@@ -23,8 +23,8 @@ namespace math { namespace detail {
   else if (lhs lexpr < rhs rexpr) return 1
   int compare(data_type const & rhs, data_type const & lhs, size_t offset) {
     IMPL_COMPARE(.size(), .size()+offset);
-    for (size_t i = rhs.size(); i > 0; --i) {
-      IMPL_COMPARE([i-1], [i+offset-1]);
+    for (size_t i = lhs.size(); i > 0; --i) {
+      IMPL_COMPARE([i+offset-1], [i-1]);
     }
     return 0;
   }
@@ -99,9 +99,7 @@ namespace math { namespace detail {
     }
     while (rhs.back() == 0) { rhs.pop_back(); }
   }
-  
-  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; }