浏览代码

Adding division with initial test cases (not complete).
Cleaning up some code.

Samuel Jaffe 8 年之前
父节点
当前提交
686f869964
共有 3 个文件被更改,包括 42 次插入6 次删除
  1. 1 0
      include/bigdecimal.h
  2. 29 6
      src/bigdecimal.cpp
  3. 12 0
      test/bigdecimal.t.h

+ 1 - 0
include/bigdecimal.h

@@ -51,6 +51,7 @@ namespace math {
     friend bigdecimal operator+(bigdecimal, bigdecimal const &);
     friend bigdecimal operator-(bigdecimal, bigdecimal const &);
     friend bigdecimal operator*(bigdecimal, bigdecimal const &);
+    friend bigdecimal operator/(bigdecimal, bigdecimal const &);
     friend bigdecimal & operator+=(bigdecimal &, bigdecimal const &);
     friend bigdecimal & operator-=(bigdecimal &, bigdecimal const &);
     friend bigdecimal & operator*=(bigdecimal &, bigdecimal const &);

+ 29 - 6
src/bigdecimal.cpp

@@ -127,7 +127,7 @@ bigdecimal & math::operator-=(bigdecimal & rhs, bigdecimal const & lhs) {
   rhs.rescale(new_scale);
   size_t const offset = size_t(rhs.get_impl_scale() - lhs.get_impl_scale());
   if (lhs == bigdecimal::ZERO) { return rhs; }
-  else if (rhs == bigdecimal::ZERO) { rhs = -lhs; }
+  else if (rhs == bigdecimal::ZERO) { rhs.set_value(-lhs); }
   else if (rhs.is_negative != lhs.is_negative) {
     detail::add(rhs.data, lhs.data, offset);
   } else {
@@ -141,19 +141,38 @@ bigdecimal & math::operator*=(bigdecimal & rhs, bigdecimal const & lhs) {
   size_t const offset = mul_scale(rhs.scale_) + mul_scale(lhs.scale_) - mul_scale(new_scale);
   bool is_neg = rhs.is_negative != lhs.is_negative;
   if (rhs == bigdecimal::ZERO || lhs == bigdecimal::ZERO) {
-    rhs.set_value(bigdecimal::ZERO);
-    rhs.rescale(new_scale);
+    rhs = bigdecimal::ZERO;
   } else if (detail::compare(lhs.data, bigdecimal::ONE.data) == 0) {
     rhs.is_negative = is_neg;
-    rhs.rescale(new_scale);
   } else if (detail::compare(rhs.data, bigdecimal::ONE.data) == 0) {
-    rhs.data = lhs.data;
+    rhs = lhs;
     rhs.is_negative = is_neg;
-    rhs.rescale(new_scale);
   } else {
     detail::multiply(rhs.data, lhs.data, offset);
     rhs.scale_ = new_scale; // TODO: more steps in certain cases
+    return rhs;
   }
+  rhs.rescale(new_scale);
+  return rhs;
+}
+
+bigdecimal & math::operator/=(bigdecimal & rhs, bigdecimal const & lhs) {
+  int32_t const new_scale = rhs.scale_ - lhs.scale_;
+  rhs.is_negative ^= lhs.is_negative;
+  if (lhs == bigdecimal::ZERO) { throw std::domain_error("cannot divide by 0"); }
+  else if (rhs == bigdecimal::ZERO) {
+    rhs = bigdecimal::ZERO;
+  } else if (detail::compare(lhs.data, bigdecimal::ONE.data) != 0) {
+    auto cmp = detail::compare(rhs.data, lhs.data);
+    if (cmp < 0) { rhs = bigdecimal::ZERO; }
+    else if (cmp == 0) { rhs.data = {1}; }
+    else {
+      rhs.data = detail::divide(rhs.data, lhs.data);
+      rhs.scale_ = new_scale;
+      return rhs;
+    }
+  }
+  rhs.rescale(new_scale);
   return rhs;
 }
 
@@ -169,6 +188,10 @@ bigdecimal math::operator*(bigdecimal rhs, bigdecimal const & lhs) {
   return rhs *= lhs;
 }
 
+bigdecimal math::operator/(bigdecimal rhs, bigdecimal const & lhs) {
+  return rhs /= lhs;
+}
+
 bool math::operator==(bigdecimal const & lhs, bigdecimal const & rhs) {
   return lhs.is_negative == rhs.is_negative && detail::compare(lhs.data, rhs.data) == 0; // TODO
 }

+ 12 - 0
test/bigdecimal.t.h

@@ -97,4 +97,16 @@ public:
     math::bigdecimal b("100", -2);
     TS_ASSERT_EQUALS((a*b).to_string(), "1");
   }
+  
+  void testDivideHigherScaleByLowerScale() {
+    math::bigdecimal a("1", 2);
+    math::bigdecimal b("1", 1);
+    TS_ASSERT_EQUALS((a/b).to_string(), "1.0");
+  }
+
+  void testDivideLowerScaleByHigherScale() {
+    math::bigdecimal a("10", 1);
+    math::bigdecimal b("1", 2);
+    TS_ASSERT_EQUALS((a/b).to_string(), "10");
+  }
 };