浏览代码

Marking +/- as taking rhs by value. This optimizes chaining operations (A+B+C+D+...).
Refactoring to use += in these cases, instead of having += use swap.

Samuel Jaffe 8 年之前
父节点
当前提交
b0db727c7d
共有 2 个文件被更改,包括 52 次插入57 次删除
  1. 2 2
      include/biginteger.h
  2. 50 55
      src/biginteger.cpp

+ 2 - 2
include/biginteger.h

@@ -29,8 +29,8 @@ namespace math {
     // Unary operators
     biginteger operator-() const;
     // Binary operators
-    friend biginteger operator+(biginteger const &, biginteger const &);
-    friend biginteger operator-(biginteger const &, biginteger const &);
+    friend biginteger operator+(biginteger, biginteger const &);
+    friend biginteger operator-(biginteger, biginteger const &);
     friend biginteger operator*(biginteger const &, biginteger const &);
     friend biginteger operator/(biginteger const &, biginteger const &);
     friend biginteger operator%(biginteger const &, biginteger const &);

+ 50 - 55
src/biginteger.cpp

@@ -18,8 +18,8 @@ namespace detail {
   using data_type = biginteger::data_type;
   // 1 => GREATER, 0 => EQUAL, -1 => LESS
   int compare(data_type const & rhs, data_type const & lhs);
-  data_type add(data_type rhs, data_type const & lhs);
-  data_type subtract_nounderflow(data_type rhs, data_type const & lhs);
+  void add(data_type & rhs, data_type const & lhs);
+  void subtract_nounderflow(data_type & rhs, data_type const & lhs);
   data_type multiply(data_type const & rhs, data_type const & lhs);
   std::pair<data_type, data_type> divide(data_type remainder, data_type const & divisor);
 }
@@ -78,22 +78,52 @@ is_negative(neg) {
 biginteger::biginteger(bool neg, data_type && dt) :
 is_negative(neg), data(std::move(dt)) {}
 
-biginteger & operator+=(biginteger & rhs, biginteger const & lhs) {
-  swap(rhs, rhs + lhs);
+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);
+    }
+  }
   return rhs;
 }
 
-biginteger & operator-=(biginteger & rhs, biginteger const & lhs) {
-  swap(rhs, rhs - lhs);
+biginteger & math::operator-=(biginteger & rhs, biginteger const & lhs) {
+  if (lhs == biginteger::ZERO) { return rhs; }
+  else if (rhs == biginteger::ZERO) { rhs = -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);;
+    }
+  }
   return rhs;
 }
 
-biginteger & operator*=(biginteger & rhs, biginteger const & lhs) {
+biginteger & math::operator*=(biginteger & rhs, biginteger const & lhs) {
   swap(rhs, rhs * lhs);
   return rhs;
 }
 
-biginteger & operator/=(biginteger & rhs, biginteger const & lhs) {
+biginteger & math::operator/=(biginteger & rhs, biginteger const & lhs) {
   swap(rhs, rhs / lhs);
   return rhs;
 }
@@ -102,38 +132,12 @@ biginteger biginteger::operator-() const {
   return (*this) * NEGATIVE_ONE;
 }
 
-biginteger math::operator+(biginteger const & rhs, biginteger const & lhs) {
-  if (lhs == biginteger::ZERO) { return rhs; }
-  else if (rhs == biginteger::ZERO) { return lhs; }
-  if (rhs.is_negative == lhs.is_negative) {
-    return {rhs.is_negative, detail::add(rhs.data, lhs.data)};
-  } else {
-    auto cmp = detail::compare(rhs.data, lhs.data);
-    if (cmp == 0) {
-      return biginteger::ZERO;
-    } else if (cmp > 0) {
-      return {rhs.is_negative, detail::subtract_nounderflow(rhs.data, lhs.data)};
-    } else {
-      return {lhs.is_negative, detail::subtract_nounderflow(lhs.data, rhs.data)};
-    }
-  }
+biginteger math::operator+(biginteger rhs, biginteger const & lhs) {
+  return rhs += lhs;
 }
 
-biginteger math::operator-(biginteger const & rhs, biginteger const & lhs) {
-  if (lhs == biginteger::ZERO) { return rhs; }
-  else if (rhs == biginteger::ZERO) { return -lhs; }
-  if (rhs.is_negative != lhs.is_negative) {
-    return {rhs.is_negative, detail::add(rhs.data, lhs.data)};
-  } else {
-    auto cmp = detail::compare(rhs.data, lhs.data);
-    if (cmp == 0) {
-      return biginteger::ZERO;
-    } else if (cmp > 0) {
-      return {rhs.is_negative, detail::subtract_nounderflow(rhs.data, lhs.data)};
-    } else {
-      return {!lhs.is_negative, detail::subtract_nounderflow(lhs.data, rhs.data)};
-    }
-  }
+biginteger math::operator-(biginteger rhs, biginteger const & lhs) {
+  return rhs -= lhs;
 }
 
 biginteger math::operator*(biginteger const & rhs, biginteger const & lhs) {
@@ -169,10 +173,11 @@ biginteger math::operator%(biginteger const & rhs, biginteger const & lhs) {
       auto data = detail::divide(rhs.data, lhs.data).second;
       if (detail::compare(data, {0}) == 0) { return biginteger::ZERO; }
       else if (rhs.is_negative != lhs.is_negative) {
-        return {lhs.is_negative, detail::subtract_nounderflow(lhs.data, data)};
-      } else {
-        return {lhs.is_negative, std::move(data)};
+        auto tmp = lhs.data;
+        swap(data, tmp);
+        detail::subtract_nounderflow(data, tmp);
       }
+      return {lhs.is_negative, std::move(data)};
     }
   }
 }
@@ -191,7 +196,7 @@ namespace detail {
   }
 #undef IMPL_COMPARE
   
-  void add_into(data_type & rhs, data_type const & lhs) {
+  void add(data_type & rhs, data_type const & lhs) {
     rhs.resize(std::max(rhs.size(), lhs.size())+1);
     auto const lbnd = lhs.size(), ubnd = rhs.size() - 1;
     // Add
@@ -208,12 +213,7 @@ namespace detail {
     if (rhs[ubnd] == 0) { rhs.pop_back(); }
   }
   
-  data_type add(data_type rhs, data_type const & lhs) {
-    add_into(rhs, lhs);
-    return rhs;
-  }
-  
-  void subtract_from(data_type & rhs, data_type const & lhs) {
+  void subtract_nounderflow(data_type & rhs, data_type const & lhs) {
     size_t const rbnd = rhs.size(), lbnd = lhs.size();
     // Subtract
     for (size_t i = 0; i < lbnd; ++i) {
@@ -229,11 +229,6 @@ namespace detail {
     if (rhs[rbnd-1] == 0 && rbnd > 1) { rhs.pop_back(); }
   }
   
-  data_type subtract_nounderflow(data_type rhs, data_type const & lhs) {
-    subtract_from(rhs, lhs);
-    return rhs;
-  }
-  
   data_type multiply(data_type const & rhs, data_type const & lhs) {
     if (compare(rhs, {1}) == 0) { return lhs; }
     else if (compare(lhs, {1}) == 0) { return rhs; }
@@ -296,8 +291,8 @@ namespace detail {
       data_type step{shift10({1}, powers[ipow], shift)};
       data_type value{shift10(divisor, powers[ipow], shift)};
       do {
-        subtract_from(remainder, value);
-        add_into(accum, step);
+        subtract_nounderflow(remainder, value);
+        add(accum, step);
       } while (detail::compare(remainder, value) >= 0);
     } while (detail::compare(remainder, divisor) >= 0);
     return { std::move(accum), std::move(remainder) };