浏览代码

Moving helper functions in detail to a separate source file.

Samuel Jaffe 8 年之前
父节点
当前提交
ca146022fe
共有 4 个文件被更改,包括 166 次插入127 次删除
  1. 12 0
      bigdecimal.xcodeproj/project.pbxproj
  2. 20 0
      include/bignum_helper.h
  3. 1 127
      src/biginteger.cpp
  4. 133 0
      src/bignum_helper.cpp

+ 12 - 0
bigdecimal.xcodeproj/project.pbxproj

@@ -7,6 +7,10 @@
 	objects = {
 
 /* Begin PBXBuildFile section */
+		CD2EC1C21F0BCCA700D49DF5 /* bignum_helper.h in Headers */ = {isa = PBXBuildFile; fileRef = CD2EC1C11F0BCCA700D49DF5 /* bignum_helper.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		CD2EC1C31F0BCCA700D49DF5 /* bignum_helper.h in Headers */ = {isa = PBXBuildFile; fileRef = CD2EC1C11F0BCCA700D49DF5 /* bignum_helper.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		CD2EC1C51F0BCCBF00D49DF5 /* bignum_helper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD2EC1C41F0BCCBF00D49DF5 /* bignum_helper.cpp */; };
+		CD2EC1C61F0BCCBF00D49DF5 /* bignum_helper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD2EC1C41F0BCCBF00D49DF5 /* bignum_helper.cpp */; };
 		CD5FB2911F06EFEF005A0D61 /* biginteger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD5FB2801F06EF7D005A0D61 /* biginteger.cpp */; };
 		CD5FB2921F06EFF2005A0D61 /* biginteger.h in Headers */ = {isa = PBXBuildFile; fileRef = CD5FB27F1F06EF70005A0D61 /* biginteger.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		CD5FB2A31F06F03D005A0D61 /* biginteger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD5FB2801F06EF7D005A0D61 /* biginteger.cpp */; };
@@ -27,6 +31,8 @@
 /* End PBXCopyFilesBuildPhase section */
 
 /* Begin PBXFileReference section */
+		CD2EC1C11F0BCCA700D49DF5 /* bignum_helper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bignum_helper.h; sourceTree = "<group>"; };
+		CD2EC1C41F0BCCBF00D49DF5 /* bignum_helper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = bignum_helper.cpp; sourceTree = "<group>"; };
 		CD5FB2711F06EEAF005A0D61 /* bigdecimal_tc */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = bigdecimal_tc; sourceTree = BUILT_PRODUCTS_DIR; };
 		CD5FB27E1F06EF64005A0D61 /* biginteger.t.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = biginteger.t.h; sourceTree = "<group>"; };
 		CD5FB27F1F06EF70005A0D61 /* biginteger.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = biginteger.h; sourceTree = "<group>"; };
@@ -86,6 +92,7 @@
 			isa = PBXGroup;
 			children = (
 				CD5FB27F1F06EF70005A0D61 /* biginteger.h */,
+				CD2EC1C11F0BCCA700D49DF5 /* bignum_helper.h */,
 			);
 			path = include;
 			sourceTree = "<group>";
@@ -94,6 +101,7 @@
 			isa = PBXGroup;
 			children = (
 				CD5FB2801F06EF7D005A0D61 /* biginteger.cpp */,
+				CD2EC1C41F0BCCBF00D49DF5 /* bignum_helper.cpp */,
 			);
 			path = src;
 			sourceTree = "<group>";
@@ -115,6 +123,7 @@
 			buildActionMask = 2147483647;
 			files = (
 				CD5FB2921F06EFF2005A0D61 /* biginteger.h in Headers */,
+				CD2EC1C21F0BCCA700D49DF5 /* bignum_helper.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -122,6 +131,7 @@
 			isa = PBXHeadersBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				CD2EC1C31F0BCCA700D49DF5 /* bignum_helper.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -251,6 +261,7 @@
 			buildActionMask = 2147483647;
 			files = (
 				CD5FB2911F06EFEF005A0D61 /* biginteger.cpp in Sources */,
+				CD2EC1C51F0BCCBF00D49DF5 /* bignum_helper.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -259,6 +270,7 @@
 			buildActionMask = 2147483647;
 			files = (
 				CD5FB2A31F06F03D005A0D61 /* biginteger.cpp in Sources */,
+				CD2EC1C61F0BCCBF00D49DF5 /* bignum_helper.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

+ 20 - 0
include/bignum_helper.h

@@ -0,0 +1,20 @@
+//
+//  bignum_helper.h
+//  bigdecimal
+//
+//  Created by Sam Jaffe on 7/4/17.
+//
+
+#pragma once
+
+#include <vector>
+
+namespace math { namespace detail {
+  using data_type = std::vector<int32_t>;
+  // 1 => GREATER, 0 => EQUAL, -1 => LESS
+  int compare(data_type const & rhs, data_type const & lhs);
+  void add(data_type & rhs, data_type const & lhs);
+  void subtract_nounderflow(data_type & rhs, data_type const & lhs);
+  void multiply(data_type & rhs, data_type const & lhs);
+  data_type divide(data_type & remainder, data_type const & divisor);
+} }

+ 1 - 127
src/biginteger.cpp

@@ -6,24 +6,14 @@
 //
 
 #include "biginteger.h"
+#include "bignum_helper.h"
 
-#include <cmath>
 #include <cstdio>
 #include <cstdlib>
 #include <cstring>
 
 using namespace math;
 
-namespace detail {
-  using data_type = biginteger::data_type;
-  // 1 => GREATER, 0 => EQUAL, -1 => LESS
-  int compare(data_type const & rhs, data_type const & lhs);
-  void add(data_type & rhs, data_type const & lhs);
-  void subtract_nounderflow(data_type & rhs, data_type const & lhs);
-  void multiply(data_type & rhs, data_type const & lhs);
-  data_type divide(data_type & remainder, data_type const & divisor);
-}
-
 biginteger::biginteger()
 : biginteger(false, 0) {}
 
@@ -167,122 +157,6 @@ biginteger math::operator%(biginteger rhs, biginteger const & lhs) {
   }
 }
 
-namespace detail {
-#define IMPL_COMPARE(expr) \
-  if (rhs expr < lhs expr) return -1; \
-  else if (lhs expr < rhs expr) return 1
-  
-  int compare(data_type const & rhs, data_type const & lhs) {
-    IMPL_COMPARE(.size());
-    for (size_t i = rhs.size(); i > 0; --i) {
-      IMPL_COMPARE([i-1]);
-    }
-    return 0;
-  }
-#undef IMPL_COMPARE
-  
-  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
-    for (size_t i = 0; i < lbnd; ++i) {
-      rhs[i] += lhs[i];
-    }
-    // Carry
-    for (size_t i = 0; i < ubnd; ++i) {
-      if (rhs[i] > biginteger::MAX_SEG) {
-        rhs[i] -= biginteger::OVER_SEG;
-        rhs[i+1] += 1;
-      }
-    }
-    if (rhs[ubnd] == 0) { rhs.pop_back(); }
-  }
-  
-  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) {
-      rhs[i] -= lhs[i];
-    }
-    // Borrow
-    for (size_t i = 0; i < rbnd; ++i) {
-      if (rhs[i] < 0) {
-        rhs[i] += biginteger::OVER_SEG;
-        rhs[i+1] -= 1;
-      }
-    }
-    if (rhs[rbnd-1] == 0 && rbnd > 1) { rhs.pop_back(); }
-  }
-  
-  void multiply(data_type & rhs, data_type const & lhs) {
-    size_t const rbnd = rhs.size(), lbnd = lhs.size();
-    size_t const ubnd = rbnd + lbnd;
-    rhs.resize(ubnd);
-    // Multiply
-    for (size_t i = rbnd; i > 0; --i) {
-      int32_t const value = rhs[i-1];
-      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 overflow = product / biginteger::OVER_SEG;
-        rhs[i+j-2] += static_cast<int32_t>(product - (overflow * biginteger::OVER_SEG));
-        rhs[i+j-1] += static_cast<int32_t>(overflow);
-      }
-      rhs[i-1] -= value;
-    }
-    // Carry
-    for (size_t i = 0; i < ubnd-1; ++i) {
-      if (rhs[i] > biginteger::MAX_SEG) {
-        int32_t overflow = rhs[i] / biginteger::OVER_SEG;
-        rhs[i] -= (overflow * biginteger::OVER_SEG);
-        rhs[i+1] += overflow;
-      }
-    }
-    while (rhs.back() == 0) { rhs.pop_back(); }
-  }
-  
-  data_type shift10(data_type const & data, int32_t pow, size_t shift) {
-    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);
-      int64_t overflow = product / biginteger::OVER_SEG;
-      rval[i+shift] += static_cast<int32_t>(product - (overflow * biginteger::OVER_SEG));
-      rval[i+shift+1] += static_cast<int32_t>(overflow);
-    }
-    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;
-  }
-  
-  size_t digits(data_type const & data) {
-    return biginteger::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);
-    do {
-      auto const diff = std::max(1UL, digits(remainder) - dig) - 1;
-      auto const shift = diff / biginteger::SEG_DIGITS;
-      auto const ipow = diff - (shift * biginteger::SEG_DIGITS);
-      data_type step{shift10({1}, powers[ipow], shift)};
-      data_type value{shift10(divisor, powers[ipow], shift)};
-      do {
-        subtract_nounderflow(remainder, value);
-        add(accum, step);
-      } while (detail::compare(remainder, value) >= 0);
-    } while (detail::compare(remainder, divisor) >= 0);
-    return accum;
-  }
-}
-
 bool math::operator==(biginteger const & rhs, biginteger const & lhs) {
   return rhs.is_negative == lhs.is_negative && detail::compare(rhs.data, lhs.data) == 0;
 }

+ 133 - 0
src/bignum_helper.cpp

@@ -0,0 +1,133 @@
+//
+//  bignum_helper.cpp
+//  bigdecimal
+//
+//  Created by Sam Jaffe on 7/4/17.
+//
+
+#include "bignum_helper.h"
+
+#include <cmath>
+
+using namespace math::detail;
+
+namespace {
+  constexpr int32_t const MAX_SEG { 999999999};
+  constexpr int32_t const OVER_SEG{1000000000};
+  constexpr int32_t const SEG_DIGITS{9};
+}
+
+namespace math { namespace detail {
+#define IMPL_COMPARE(expr) \
+  if (rhs expr < lhs expr) return -1; \
+  else if (lhs expr < rhs expr) return 1
+  int compare(data_type const & rhs, data_type const & lhs) {
+    IMPL_COMPARE(.size());
+    for (size_t i = rhs.size(); i > 0; --i) {
+      IMPL_COMPARE([i-1]);
+    }
+    return 0;
+  }
+#undef IMPL_COMPARE
+  
+  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
+    for (size_t i = 0; i < lbnd; ++i) {
+      rhs[i] += lhs[i];
+    }
+    // Carry
+    for (size_t i = 0; i < ubnd; ++i) {
+      if (rhs[i] > MAX_SEG) {
+        rhs[i] -= OVER_SEG;
+        rhs[i+1] += 1;
+      }
+    }
+    if (rhs[ubnd] == 0) { rhs.pop_back(); }
+  }
+  
+  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) {
+      rhs[i] -= lhs[i];
+    }
+    // Borrow
+    for (size_t i = 0; i < rbnd; ++i) {
+      if (rhs[i] < 0) {
+        rhs[i] += OVER_SEG;
+        rhs[i+1] -= 1;
+      }
+    }
+    if (rhs[rbnd-1] == 0 && rbnd > 1) { rhs.pop_back(); }
+  }
+  
+  void multiply(data_type & rhs, data_type const & lhs) {
+    size_t const rbnd = rhs.size(), lbnd = lhs.size();
+    size_t const ubnd = rbnd + lbnd;
+    rhs.resize(ubnd);
+    // Multiply
+    for (size_t i = rbnd; i > 0; --i) {
+      int32_t const value = rhs[i-1];
+      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 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-1] -= value;
+    }
+    // Carry
+    for (size_t i = 0; i < ubnd-1; ++i) {
+      if (rhs[i] > MAX_SEG) {
+        int32_t overflow = rhs[i] / OVER_SEG;
+        rhs[i] -= (overflow * OVER_SEG);
+        rhs[i+1] += overflow;
+      }
+    }
+    while (rhs.back() == 0) { rhs.pop_back(); }
+  }
+  
+  data_type shift10(data_type const & data, int32_t pow, size_t shift) {
+    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);
+      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);
+    }
+    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;
+  }
+  
+  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);
+    do {
+      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 step{shift10({1}, powers[ipow], shift)};
+      data_type value{shift10(divisor, powers[ipow], shift)};
+      do {
+        subtract_nounderflow(remainder, value);
+        add(accum, step);
+      } while (compare(remainder, value) >= 0);
+    } while (compare(remainder, divisor) >= 0);
+    return accum;
+  }
+} }