gnucash master: Multiple changes pushed

John Ralls jralls at code.gnucash.org
Fri Dec 5 19:57:10 EST 2014


Updated	 via  https://github.com/Gnucash/gnucash/commit/ae7e9c24 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/8a3e3687 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/d35bcdb8 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/8e429f74 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/79938cae (commit)
	 via  https://github.com/Gnucash/gnucash/commit/7c7946de (commit)
	 via  https://github.com/Gnucash/gnucash/commit/503a6070 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/456e1219 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/b694df72 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/701d8030 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/c4d649bc (commit)
	 via  https://github.com/Gnucash/gnucash/commit/33a0c4e9 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/ab940945 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/a9933510 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/f4c69dbc (commit)
	 via  https://github.com/Gnucash/gnucash/commit/9e37ad27 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/f5c7b110 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/765d5583 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/7c22669a (commit)
	 via  https://github.com/Gnucash/gnucash/commit/296ce314 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/1b288df2 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/c649aa97 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/810a6bc8 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/1c83db58 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/c7752d5d (commit)
	 via  https://github.com/Gnucash/gnucash/commit/1e6855ef (commit)
	 via  https://github.com/Gnucash/gnucash/commit/d4fdd9ef (commit)
	 via  https://github.com/Gnucash/gnucash/commit/9d029d7f (commit)
	 via  https://github.com/Gnucash/gnucash/commit/996345a0 (commit)
	from  https://github.com/Gnucash/gnucash/commit/3c46aac9 (commit)



commit ae7e9c24121671f536db7d07505d582d6b0c057f
Merge: 996345a 8a3e368
Author: John Ralls <jralls at ceridwen.us>
Date:   Fri Dec 5 15:47:54 2014 -0800

    Merge branch 'c++-numeric'
    
    A new C++ implementation of 128-bit math replaces qofmath128.c with
    gnc-int128.cpp, and the gnc-numeric arithmetic operations now wrap
    the equivalent functions in a new GncRational class, which works with
    a GncDenom class to handle rounding and denominator-type settings.
    
    All arithmetic is now done with 128 bits of precision and no overflows
    are signalled until conversion back to the int64_t-based gnc_numeric.
    C++ clients will be able to use GncRational directly, at which point
    some of its other functionality can be added; this will allow chained
    128-bit arithmetic, which will permit more complicated calculations
    without overflow.
    
    Operators are not implemented for GncRational (they are for GncInt128,
    which makes the GncRational implemntation much easier to read) because
    of the need for passing denominator and rounding specs.


commit 8a3e3687912b67df2d36dfb2ca1d4aadb0773c5b
Author: John Ralls <jralls at ceridwen.us>
Date:   Fri Dec 5 15:46:07 2014 -0800

    Rename QofInt128 to GncInt128.
    
    It has nothing to do with QOF.

diff --git a/po/POTFILES.in b/po/POTFILES.in
index 4acbea6..f4cb487 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -429,6 +429,7 @@ src/import-export/qif-imp/gncmod-qif-import.c
 src/import-export/qif-imp/gnc-plugin-qif-import.c
 [type: gettext/gsettings]src/import-export/qif-imp/gschemas/org.gnucash.dialogs.import.qif.gschema.xml.in.in
 src/libqof/qof/gnc-date.cpp
+src/libqof/qof/gnc-int128.cpp
 src/libqof/qof/gnc-numeric.cpp
 src/libqof/qof/gnc-rational.cpp
 src/libqof/qof/guid.cpp
@@ -442,7 +443,6 @@ src/libqof/qof/qofevent.cpp
 src/libqof/qof/qofid.cpp
 src/libqof/qof/qofinstance.cpp
 src/libqof/qof/qoflog.cpp
-src/libqof/qof/qofint128.cpp
 src/libqof/qof/qofobject.cpp
 src/libqof/qof/qofquerycore.cpp
 src/libqof/qof/qofquery.cpp
diff --git a/src/libqof/qof/Makefile.am b/src/libqof/qof/Makefile.am
index 0648195..a873164 100644
--- a/src/libqof/qof/Makefile.am
+++ b/src/libqof/qof/Makefile.am
@@ -24,6 +24,7 @@ AM_CPPFLAGS = \
 
 libgnc_qof_la_SOURCES =  \
    gnc-date.cpp        \
+   gnc-int128.cpp      \
    gnc-numeric.cpp     \
    gnc-rational.cpp    \
    guid.cpp            \
@@ -37,7 +38,6 @@ libgnc_qof_la_SOURCES =  \
    qofevent.cpp        \
    qofid.cpp           \
    qofinstance.cpp     \
-   qofint128.cpp       \
    qoflog.cpp          \
    qofobject.cpp       \
    qofquery.cpp        \
@@ -82,7 +82,7 @@ noinst_HEADERS = \
    qofbook-p.h  \
    qofclass-p.h  \
    qofevent-p.h \
-   qofint128.hpp  \
+   gnc-int128.hpp  \
    qofobject-p.h  \
    qofquery-p.h  \
    qofquerycore-p.h \
diff --git a/src/libqof/qof/qofint128.cpp b/src/libqof/qof/gnc-int128.cpp
similarity index 83%
rename from src/libqof/qof/qofint128.cpp
rename to src/libqof/qof/gnc-int128.cpp
index 97e7fd8..d87b5b3 100644
--- a/src/libqof/qof/qofint128.cpp
+++ b/src/libqof/qof/gnc-int128.cpp
@@ -27,7 +27,7 @@ extern "C"
 #include <inttypes.h>
 }
 
-#include "qofint128.hpp"
+#include "gnc-int128.hpp"
 
 #include <iomanip>
 #include <utility>
@@ -39,22 +39,22 @@ extern "C"
  */
 
 namespace {
-    static const uint sublegs = QofInt128::numlegs * 2;
-    static const uint sublegbits = QofInt128::legbits / 2;
+    static const uint sublegs = GncInt128::numlegs * 2;
+    static const uint sublegbits = GncInt128::legbits / 2;
     static const uint64_t sublegmask = (UINT64_C(1) << sublegbits) - 1;
 }
 
-QofInt128::QofInt128 () : m_flags {}, m_hi {0}, m_lo {0}{}
+GncInt128::GncInt128 () : m_flags {}, m_hi {0}, m_lo {0}{}
 
-QofInt128::QofInt128 (int64_t lower) :
+GncInt128::GncInt128 (int64_t lower) :
     m_flags {static_cast<unsigned char>(lower < 0 ? neg : pos)},
     m_hi {0},
     m_lo {static_cast<uint64_t>(lower < 0 ? -lower : lower)} {}
 
-QofInt128::QofInt128 (uint64_t lower) :
+GncInt128::GncInt128 (uint64_t lower) :
     m_flags {}, m_hi {0}, m_lo {lower} {}
 
-QofInt128::QofInt128 (int64_t upper, int64_t lower, unsigned char flags) :
+GncInt128::GncInt128 (int64_t upper, int64_t lower, unsigned char flags) :
     m_flags {static_cast<unsigned char>(flags ^ (upper < 0 ? neg :
     upper == 0 && lower < 0 ? neg : pos))},
     m_hi {static_cast<uint64_t>(upper < 0 ? -upper : upper)},
@@ -68,19 +68,19 @@ QofInt128::QofInt128 (int64_t upper, int64_t lower, unsigned char flags) :
     m_hi >>= 1;
 }
 
-QofInt128::QofInt128 (uint64_t upper, uint64_t lower, unsigned char flags) :
+GncInt128::GncInt128 (uint64_t upper, uint64_t lower, unsigned char flags) :
     m_flags {flags}, m_hi {upper},
     m_lo {lower} {}
 
-QofInt128&
-QofInt128::zero () noexcept
+GncInt128&
+GncInt128::zero () noexcept
 {
     m_flags = 0;
     m_lo = m_hi = UINT64_C(0);
     return *this;
 }
 
-QofInt128::operator int64_t() const
+GncInt128::operator int64_t() const
 {
     if ((m_flags & neg) && isBig())
         throw std::underflow_error ("Negative value to large to represent as int64_t");
@@ -90,7 +90,7 @@ QofInt128::operator int64_t() const
     return m_flags & neg ? -retval : retval;
 }
 
-QofInt128::operator uint64_t() const
+GncInt128::operator uint64_t() const
 {
     if (m_flags & neg)
         throw std::underflow_error ("Can't represent negative value as uint64_t");
@@ -101,7 +101,7 @@ QofInt128::operator uint64_t() const
 
 
 int
-QofInt128::cmp (const QofInt128& b) const noexcept
+GncInt128::cmp (const GncInt128& b) const noexcept
 {
     if (m_flags & (overflow | NaN))
         return -1;
@@ -127,8 +127,8 @@ QofInt128::cmp (const QofInt128& b) const noexcept
 /* Knuth 4.5.3 Algo B, recommended by GMP as much faster than Algo A (Euclidean
  * method).
  */
-QofInt128
-QofInt128::gcd(QofInt128 b) const noexcept
+GncInt128
+GncInt128::gcd(GncInt128 b) const noexcept
 {
     if (b.isZero())
         return *this;
@@ -140,7 +140,7 @@ QofInt128::gcd(QofInt128 b) const noexcept
     if (isOverflow() || isNan())
         return *this;
 
-    QofInt128 a (isNeg() ? -(*this) : *this);
+    GncInt128 a (isNeg() ? -(*this) : *this);
     if (b.isNeg()) b = -b;
 
     uint k {};
@@ -151,7 +151,7 @@ QofInt128::gcd(QofInt128 b) const noexcept
         b >>= 1;
         ++k;
     }
-    QofInt128 t {a & one ? -b : a}; //B2
+    GncInt128 t {a & one ? -b : a}; //B2
     while (a != b)
     {
         while (t && (t & one ^ one)) t >>= 1;  //B3 & B4
@@ -166,22 +166,22 @@ QofInt128::gcd(QofInt128 b) const noexcept
 
 /* Since u * v = gcd(u, v) * lcm(u, v), we find lcm by u / gcd * v. */
 
-QofInt128
-QofInt128::lcm(const QofInt128& b) const noexcept
+GncInt128
+GncInt128::lcm(const GncInt128& b) const noexcept
 {
     auto common = gcd(b);
     return *this / common * b.abs(); //Preserve our sign, discard the other's.
 }
 
 /* Knuth section 4.6.3 */
-QofInt128
-QofInt128::pow(uint b) const noexcept
+GncInt128
+GncInt128::pow(uint b) const noexcept
 {
     if (isZero() || (m_lo == 1 && m_hi == 0) || isNan() || isOverflow())
         return *this;
     if (b == 0)
-        return QofInt128 (1);
-    QofInt128 retval (1), squares = *this;
+        return GncInt128 (1);
+    GncInt128 retval (1), squares = *this;
     while (b && !retval.isOverflow())
     {
         if (b & 1)
@@ -193,37 +193,37 @@ QofInt128::pow(uint b) const noexcept
 }
 
 bool
-QofInt128::isNeg () const noexcept
+GncInt128::isNeg () const noexcept
 {
     return (m_flags & neg);
 }
 
 bool
-QofInt128::isBig () const noexcept
+GncInt128::isBig () const noexcept
 {
     return (m_hi || m_lo > INT64_MAX);
 }
 
 bool
-QofInt128::isOverflow () const noexcept
+GncInt128::isOverflow () const noexcept
 {
     return (m_flags & overflow);
 }
 
 bool
-QofInt128::isNan () const noexcept
+GncInt128::isNan () const noexcept
 {
     return (m_flags & NaN);
 }
 
 bool
-QofInt128::isZero() const noexcept
+GncInt128::isZero() const noexcept
 {
     return ((m_flags & (overflow | NaN)) == 0 &&  m_hi == 0 && m_lo == 0);
 }
 
-QofInt128
-QofInt128::abs() const noexcept
+GncInt128
+GncInt128::abs() const noexcept
 {
     if (isNeg())
         return operator-();
@@ -232,7 +232,7 @@ QofInt128::abs() const noexcept
 }
 
 uint
-QofInt128::bits() const noexcept
+GncInt128::bits() const noexcept
 {
     uint bits {static_cast<uint>(m_hi == 0 ? 0 : 64)};
     uint64_t temp {(m_hi == 0 ? m_lo : m_hi)};
@@ -242,8 +242,8 @@ QofInt128::bits() const noexcept
 }
 
 
-QofInt128
-QofInt128::operator-() const noexcept
+GncInt128
+GncInt128::operator-() const noexcept
 {
     auto retval = *this;
     if (isNeg())
@@ -253,37 +253,37 @@ QofInt128::operator-() const noexcept
     return retval;
 }
 
-QofInt128::operator bool() const noexcept
+GncInt128::operator bool() const noexcept
 {
     return ! isZero ();
 }
 
-QofInt128&
-QofInt128::operator++ () noexcept
+GncInt128&
+GncInt128::operator++ () noexcept
 {
     return operator+=(UINT64_C(1));
 }
 
-QofInt128&
-QofInt128::operator++ (int) noexcept
+GncInt128&
+GncInt128::operator++ (int) noexcept
 {
     return operator+=(UINT64_C(1));
 }
 
-QofInt128&
-QofInt128::operator-- () noexcept
+GncInt128&
+GncInt128::operator-- () noexcept
 {
     return operator-=(UINT64_C(1));
 }
 
-QofInt128&
-QofInt128::operator-- (int) noexcept
+GncInt128&
+GncInt128::operator-- (int) noexcept
 {
     return operator-=(UINT64_C(1));
 }
 
-QofInt128&
-QofInt128::operator+= (const QofInt128& b) noexcept
+GncInt128&
+GncInt128::operator+= (const GncInt128& b) noexcept
 {
     if (b.isOverflow())
         m_flags |= overflow;
@@ -304,8 +304,8 @@ QofInt128::operator+= (const QofInt128& b) noexcept
     return *this;
 }
 
-QofInt128&
-QofInt128::operator<<= (uint i) noexcept
+GncInt128&
+GncInt128::operator<<= (uint i) noexcept
 {
     if (i > maxbits)
     {
@@ -321,8 +321,8 @@ QofInt128::operator<<= (uint i) noexcept
     return *this;
 }
 
-QofInt128&
-QofInt128::operator>>= (uint i) noexcept
+GncInt128&
+GncInt128::operator>>= (uint i) noexcept
 {
     if (i > maxbits)
     {
@@ -338,8 +338,8 @@ QofInt128::operator>>= (uint i) noexcept
     return *this;
 }
 
-QofInt128&
-QofInt128::operator-= (const QofInt128& b) noexcept
+GncInt128&
+GncInt128::operator-= (const GncInt128& b) noexcept
 {
     if (b.isOverflow())
         m_flags |= overflow;
@@ -383,8 +383,8 @@ QofInt128::operator-= (const QofInt128& b) noexcept
     return *this;
 }
 
-QofInt128&
-QofInt128::operator*= (const QofInt128& b) noexcept
+GncInt128&
+GncInt128::operator*= (const GncInt128& b) noexcept
 {
     /* Test for 0 first */
     if (isZero() || b.isZero())
@@ -423,7 +423,7 @@ QofInt128::operator*= (const QofInt128& b) noexcept
     }
 
 /* This is Knuth's "classical" multi-precision multiplication algorithm
- * truncated to a QofInt128 result with the loop unrolled for clarity and with
+ * truncated to a GncInt128 result with the loop unrolled for clarity and with
  * overflow and zero checks beforehand to save time. See Donald Knuth, "The Art
  * of Computer Programming Volume 2: Seminumerical Algorithms", Addison-Wesley,
  * 1998, p 268.
@@ -488,7 +488,7 @@ namespace {
  */
 /* We're using arrays here instead of vectors to avoid an alloc. */
 void
-div_multi_leg (uint64_t* u, size_t m, uint64_t* v, size_t n, QofInt128& q, QofInt128& r) noexcept
+div_multi_leg (uint64_t* u, size_t m, uint64_t* v, size_t n, GncInt128& q, GncInt128& r) noexcept
 {
 /* D1, Normalization */
     uint64_t qv[sublegs] {};
@@ -578,14 +578,14 @@ div_multi_leg (uint64_t* u, size_t m, uint64_t* v, size_t n, QofInt128& q, QofIn
             u[j + n] += carry;
         }
     }//D7
-    q = QofInt128 ((qv[3] << sublegbits) + qv[2], (qv[1] << sublegbits) + qv[0]);
-    r = QofInt128 ((u[3] << sublegbits) + u[2], (u[1] << sublegbits) + u[0]);
+    q = GncInt128 ((qv[3] << sublegbits) + qv[2], (qv[1] << sublegbits) + qv[0]);
+    r = GncInt128 ((u[3] << sublegbits) + u[2], (u[1] << sublegbits) + u[0]);
     r /= d;
     if (negative) q = -q;
 }
 
 void
-div_single_leg (uint64_t* u, size_t m, uint64_t v, QofInt128& q, QofInt128& r) noexcept
+div_single_leg (uint64_t* u, size_t m, uint64_t v, GncInt128& q, GncInt128& r) noexcept
 {
     uint64_t qv[sublegs] {};
     uint64_t carry {};
@@ -602,15 +602,15 @@ div_single_leg (uint64_t* u, size_t m, uint64_t v, QofInt128& q, QofInt128& r) n
             u[i] %= v;
     }
 
-    q = QofInt128 ((qv[3] << sublegbits) + qv[2], (qv[1] << sublegbits) + qv[0]);
-    r = QofInt128 ((u[3] << sublegbits) + u[2], (u[1] << sublegbits) + u[0]);
+    q = GncInt128 ((qv[3] << sublegbits) + qv[2], (qv[1] << sublegbits) + qv[0]);
+    r = GncInt128 ((u[3] << sublegbits) + u[2], (u[1] << sublegbits) + u[0]);
     if (negative) q = -q;
 }
 
 }// namespace
 
 void
-QofInt128::div (const QofInt128& b, QofInt128& q, QofInt128& r) noexcept
+GncInt128::div (const GncInt128& b, GncInt128& q, GncInt128& r) noexcept
 {
     if (isOverflow() || b.isOverflow())
     {
@@ -670,19 +670,19 @@ QofInt128::div (const QofInt128& b, QofInt128& q, QofInt128& r) noexcept
     return div_multi_leg (u, m, v, n, q, r);
 }
 
-QofInt128&
-QofInt128::operator/= (const QofInt128& b) noexcept
+GncInt128&
+GncInt128::operator/= (const GncInt128& b) noexcept
 {
-    QofInt128 q {}, r {};
+    GncInt128 q {}, r {};
     div(b, q, r);
     std::swap (*this, q);
     return *this;
 }
 
-QofInt128&
-QofInt128::operator%= (const QofInt128& b) noexcept
+GncInt128&
+GncInt128::operator%= (const GncInt128& b) noexcept
 {
-    QofInt128 q {}, r {};
+    GncInt128 q {}, r {};
     div(b, q, r);
     std::swap (*this, r);
     if (q.isNan())
@@ -690,8 +690,8 @@ QofInt128::operator%= (const QofInt128& b) noexcept
     return *this;
 }
 
-QofInt128&
-QofInt128::operator&= (const QofInt128& b) noexcept
+GncInt128&
+GncInt128::operator&= (const GncInt128& b) noexcept
 {
     if (b.isOverflow())
         m_flags |= overflow;
@@ -706,16 +706,16 @@ QofInt128::operator&= (const QofInt128& b) noexcept
     return *this;
 }
 
-QofInt128&
-QofInt128::operator|= (const QofInt128& b) noexcept
+GncInt128&
+GncInt128::operator|= (const GncInt128& b) noexcept
 {
     m_hi ^= b.m_hi;
     m_lo ^= b.m_lo;
     return *this;
 }
 
-QofInt128&
-QofInt128::operator^= (const QofInt128& b) noexcept
+GncInt128&
+GncInt128::operator^= (const GncInt128& b) noexcept
 {
     if (b.isOverflow())
         m_flags |= overflow;
@@ -775,7 +775,7 @@ decimal_from_binary (uint64_t d[dec_array_size], uint64_t hi, uint64_t lo)
 static const uint8_t char_buf_size {41}; //39 digits plus sign and trailing null
 
 char*
-QofInt128::asCharBufR(char* buf) const noexcept
+GncInt128::asCharBufR(char* buf) const noexcept
 {
     if (isOverflow())
     {
@@ -809,7 +809,7 @@ QofInt128::asCharBufR(char* buf) const noexcept
 }
 
 std::ostream&
-operator<< (std::ostream& stream, const QofInt128& a) noexcept
+operator<< (std::ostream& stream, const GncInt128& a) noexcept
 {
     char buf[char_buf_size] {};
     stream << a.asCharBufR (buf);
@@ -817,105 +817,105 @@ operator<< (std::ostream& stream, const QofInt128& a) noexcept
 }
 
 bool
-operator== (const QofInt128& a, const QofInt128& b) noexcept
+operator== (const GncInt128& a, const GncInt128& b) noexcept
 {
     return a.cmp(b) == 0;
 }
 
 bool
-operator!= (const QofInt128& a, const QofInt128& b) noexcept
+operator!= (const GncInt128& a, const GncInt128& b) noexcept
 {
     return a.cmp(b) != 0;
 }
 
 bool
-operator< (const QofInt128& a, const QofInt128& b) noexcept
+operator< (const GncInt128& a, const GncInt128& b) noexcept
 {
     return a.cmp(b) < 0;
 }
 
 bool
-operator> (const QofInt128& a, const QofInt128& b) noexcept
+operator> (const GncInt128& a, const GncInt128& b) noexcept
 {
     return a.cmp(b) > 0;
 }
 
 bool
-operator<= (const QofInt128& a, const QofInt128& b) noexcept
+operator<= (const GncInt128& a, const GncInt128& b) noexcept
 {
     return a.cmp(b) <= 0;
 }
 
 bool
-operator>= (const QofInt128& a, const QofInt128& b) noexcept
+operator>= (const GncInt128& a, const GncInt128& b) noexcept
 {
     return a.cmp(b) >= 0;
 }
 
-QofInt128
-operator+ (QofInt128 a, const QofInt128& b) noexcept
+GncInt128
+operator+ (GncInt128 a, const GncInt128& b) noexcept
 {
     a += b;
     return a;
 }
 
-QofInt128
-operator- (QofInt128 a, const QofInt128& b) noexcept
+GncInt128
+operator- (GncInt128 a, const GncInt128& b) noexcept
 {
     a -= b;
     return a;
 }
-QofInt128
-operator* (QofInt128 a, const QofInt128& b) noexcept
+GncInt128
+operator* (GncInt128 a, const GncInt128& b) noexcept
 {
     a *= b;
     return a;
 }
 
-QofInt128
-operator/ (QofInt128 a, const QofInt128& b) noexcept
+GncInt128
+operator/ (GncInt128 a, const GncInt128& b) noexcept
 {
     a /= b;
     return a;
 }
 
-QofInt128
-operator% (QofInt128 a, const QofInt128& b) noexcept
+GncInt128
+operator% (GncInt128 a, const GncInt128& b) noexcept
 {
     a %= b;
     return a;
 }
 
-QofInt128
-operator& (QofInt128 a, const QofInt128& b) noexcept
+GncInt128
+operator& (GncInt128 a, const GncInt128& b) noexcept
 {
     a &= b;
     return a;
 }
 
-QofInt128
-operator| (QofInt128 a, const QofInt128& b) noexcept
+GncInt128
+operator| (GncInt128 a, const GncInt128& b) noexcept
 {
     a |= b;
     return a;
 }
 
-QofInt128
-operator^ (QofInt128 a, const QofInt128& b) noexcept
+GncInt128
+operator^ (GncInt128 a, const GncInt128& b) noexcept
 {
     a ^= b;
     return a;
 }
 
-QofInt128
-operator<< (QofInt128 a, uint b) noexcept
+GncInt128
+operator<< (GncInt128 a, uint b) noexcept
 {
     a <<= b;
     return a;
 }
 
-QofInt128
-operator>> (QofInt128 a, uint b) noexcept
+GncInt128
+operator>> (GncInt128 a, uint b) noexcept
 {
     a >>= b;
     return a;
diff --git a/src/libqof/qof/qofint128.hpp b/src/libqof/qof/gnc-int128.hpp
similarity index 58%
rename from src/libqof/qof/qofint128.hpp
rename to src/libqof/qof/gnc-int128.hpp
index 705ab52..efbfdba 100644
--- a/src/libqof/qof/qofint128.hpp
+++ b/src/libqof/qof/gnc-int128.hpp
@@ -22,8 +22,8 @@
  *                                                                  *
  *******************************************************************/
 
-#ifndef QOFINT128_H
-#define QOFINT128_H
+#ifndef GNCINT128_H
+#define GNCINT128_H
 
 #include <stdint.h>
 
@@ -39,12 +39,12 @@
  * All the usual operators are provided. Only the explicit integer
  * conversions throw; all other errors are indicated by the overflow
  * and NaN ("Not a Number") flags. Note that performing any operation
- * on an overflowed or NaN QofInt128 will yield an overflowed or NaN
+ * on an overflowed or NaN Gncint128 will yield an overflowed or NaN
  * result, so calling routines need not check until the end of a
  * chained calculation.
- * QofInt128 uses implicit copy and move constructors and implicit destructor.
+ * GncInt128 uses implicit copy and move constructors and implicit destructor.
  */
-class QofInt128
+class GncInt128
 {
     unsigned char m_flags;
     uint64_t m_hi;
@@ -63,35 +63,35 @@ enum // Values for m_flags
     NaN = 4
 };
 
-    QofInt128 ();
-    QofInt128 (int16_t lower) : QofInt128{static_cast<int64_t>(lower)} {};
-    QofInt128 (uint16_t lower) : QofInt128{static_cast<uint64_t>(lower)} {};
-    QofInt128 (int32_t lower) : QofInt128{static_cast<int64_t>(lower)} {};
-    QofInt128 (uint32_t lower) : QofInt128{static_cast<uint64_t>(lower)} {};
-    QofInt128 (int64_t lower);
-    QofInt128 (uint64_t lower);
+    GncInt128 ();
+    GncInt128 (int16_t lower) : GncInt128{static_cast<int64_t>(lower)} {};
+    GncInt128 (uint16_t lower) : GncInt128{static_cast<uint64_t>(lower)} {};
+    GncInt128 (int32_t lower) : GncInt128{static_cast<int64_t>(lower)} {};
+    GncInt128 (uint32_t lower) : GncInt128{static_cast<uint64_t>(lower)} {};
+    GncInt128 (int64_t lower);
+    GncInt128 (uint64_t lower);
 /**
- * Construct a QofInt128 from two int64_t.
+ * Construct a GncInt128 from two int64_t.
  *
  * N.B.: If the two parameters are of differing sign, it's taken to
  * mean that the lower magnitude is *reducing* the magnitude of the
  * upper, so the lower magnitude will be subracted from UINT64_MAX to
  * obtain the lower limb value.
  */
-    QofInt128 (int16_t upper, int16_t lower, unsigned char flags = '\0') :
-        QofInt128{static_cast<int64_t>(upper), static_cast<int64_t>(lower),
+    GncInt128 (int16_t upper, int16_t lower, unsigned char flags = '\0') :
+        GncInt128{static_cast<int64_t>(upper), static_cast<int64_t>(lower),
                       flags} {};
-    QofInt128 (uint16_t upper, uint16_t lower, unsigned char flags = '\0') :
-        QofInt128{static_cast<int64_t>(upper), static_cast<int64_t>(lower),
+    GncInt128 (uint16_t upper, uint16_t lower, unsigned char flags = '\0') :
+        GncInt128{static_cast<int64_t>(upper), static_cast<int64_t>(lower),
                       flags} {};
-    QofInt128 (int32_t upper, int32_t lower, unsigned char flags = '\0') :
-        QofInt128{static_cast<int64_t>(upper), static_cast<int64_t>(lower),
+    GncInt128 (int32_t upper, int32_t lower, unsigned char flags = '\0') :
+        GncInt128{static_cast<int64_t>(upper), static_cast<int64_t>(lower),
                       flags} {};
-    QofInt128 (uint32_t upper, uint32_t lower, unsigned char flags = '\0') :
-        QofInt128{static_cast<int64_t>(upper), static_cast<int64_t>(lower),
+    GncInt128 (uint32_t upper, uint32_t lower, unsigned char flags = '\0') :
+        GncInt128{static_cast<int64_t>(upper), static_cast<int64_t>(lower),
                       flags} {};
-    QofInt128 (int64_t upper, int64_t lower, unsigned char flags = '\0');
-    QofInt128 (uint64_t upper, uint64_t lower, unsigned char flags = '\0');
+    GncInt128 (int64_t upper, int64_t lower, unsigned char flags = '\0');
+    GncInt128 (uint64_t upper, uint64_t lower, unsigned char flags = '\0');
 
 /**
  * Clear the object.
@@ -99,7 +99,7 @@ enum // Values for m_flags
  * Sets all member variables to zero.
  * @return A reference to the object for chaining.
  */
-    QofInt128& zero() noexcept;
+    GncInt128& zero() noexcept;
 
 /**
  * Compare function.
@@ -107,29 +107,29 @@ enum // Values for m_flags
  * @return -1 if the object is less than the parameter, 0 if they're
  * equal, and 1 if the object is greater.
  */
-    int cmp (const QofInt128& b) const noexcept;
+    int cmp (const GncInt128& b) const noexcept;
 
 /**
  * Computes the Greatest Common Divisor between the object and paramter
  *
- * @return A QofInt128 having the GCD.
+ * @return A GncInt128 having the GCD.
  */
-    QofInt128 gcd (QofInt128 b) const noexcept;
+    GncInt128 gcd (GncInt128 b) const noexcept;
 /**
  * Computes the Least Common Multiple between the object and parameter
  *
- * @return A QofInt128 having the LCM.
+ * @return A GncInt128 having the LCM.
  */
-    QofInt128 lcm (const QofInt128& b) const noexcept;
+    GncInt128 lcm (const GncInt128& b) const noexcept;
 
 /**
  * Computes the object raised to the parameter's power
  *
- * @param b The power to raise this to. No point in taking a QofInt128, any
+ * @param b The power to raise this to. No point in taking a GncInt128, any
  * value greater than 128 would overflow on any value other than 1.
- * @return A QofInt128
+ * @return A GncInt128
  */
-    QofInt128 pow (uint n) const noexcept;
+    GncInt128 pow (uint n) const noexcept;
 
 /**
  * Computes a quotient and a remainder, passed as reference parameters.
@@ -140,7 +140,7 @@ enum // Values for m_flags
  * @param q The quotient; will be NaN if divisor = 0
  * @param r The remainder; will be 0 if divisor = 0
  */
-    void div (const QofInt128& d, QofInt128& q, QofInt128& r) noexcept;
+    void div (const GncInt128& d, GncInt128& q, GncInt128& r) noexcept;
 
 /**
  * Explicit conversion to int64_t.
@@ -188,7 +188,7 @@ enum // Values for m_flags
 
 /**
  * Fills a supplied buffer with a representation of the number in base 10. If
- * the QofInt128 is overflowed or NaN it will contain the words "Overflow" or
+ * the GncInt128 is overflowed or NaN it will contain the words "Overflow" or
  * "NaN" respectively.
  *
  * @param buf char[41], 39 digits plus sign and trailing 0.
@@ -196,59 +196,59 @@ enum // Values for m_flags
  */
     char* asCharBufR(char* buf) const noexcept;
 
-    QofInt128 abs() const noexcept;
+    GncInt128 abs() const noexcept;
 
-    QofInt128 operator-() const noexcept;
+    GncInt128 operator-() const noexcept;
     explicit operator bool() const noexcept;
 
-    QofInt128& operator++ () noexcept;
-    QofInt128& operator++ (int) noexcept;
-    QofInt128& operator-- () noexcept;
-    QofInt128& operator-- (int) noexcept;
-    QofInt128& operator<<= (uint i) noexcept;
-    QofInt128& operator>>= (uint i) noexcept;
-    QofInt128& operator+= (const QofInt128& b) noexcept;
-    QofInt128& operator-= (const QofInt128& b) noexcept;
-    QofInt128& operator*= (const QofInt128& b) noexcept;
-    QofInt128& operator/= (const QofInt128& b) noexcept;
-    QofInt128& operator%= (const QofInt128& b) noexcept;
-    QofInt128& operator&= (const QofInt128& b) noexcept;
-    QofInt128& operator|= (const QofInt128& b) noexcept;
-    QofInt128& operator^= (const QofInt128& b) noexcept;
+    GncInt128& operator++ () noexcept;
+    GncInt128& operator++ (int) noexcept;
+    GncInt128& operator-- () noexcept;
+    GncInt128& operator-- (int) noexcept;
+    GncInt128& operator<<= (uint i) noexcept;
+    GncInt128& operator>>= (uint i) noexcept;
+    GncInt128& operator+= (const GncInt128& b) noexcept;
+    GncInt128& operator-= (const GncInt128& b) noexcept;
+    GncInt128& operator*= (const GncInt128& b) noexcept;
+    GncInt128& operator/= (const GncInt128& b) noexcept;
+    GncInt128& operator%= (const GncInt128& b) noexcept;
+    GncInt128& operator&= (const GncInt128& b) noexcept;
+    GncInt128& operator|= (const GncInt128& b) noexcept;
+    GncInt128& operator^= (const GncInt128& b) noexcept;
 
 };
 
-static const QofInt128 k_qofInt128_Max {UINT64_MAX, UINT64_MAX, QofInt128::pos};
-static const QofInt128 k_qofInt128_Min {UINT64_MAX, UINT64_MAX, QofInt128::neg};
-
-QofInt128 operator+ (QofInt128 a, const QofInt128& b) noexcept;
-QofInt128 operator- (QofInt128 a, const QofInt128& b) noexcept;
-QofInt128 operator* (QofInt128 a, const QofInt128& b) noexcept;
-QofInt128 operator/ (QofInt128 a, const QofInt128& b) noexcept;
-QofInt128 operator% (QofInt128 a, const QofInt128& b) noexcept;
-QofInt128 operator& (QofInt128 a, const QofInt128& b) noexcept;
-QofInt128 operator| (QofInt128 a, const QofInt128& b) noexcept;
-QofInt128 operator^ (QofInt128 a, const QofInt128& b) noexcept;
-QofInt128 operator<< (QofInt128 a, uint b) noexcept;
-QofInt128 operator>> (QofInt128 a, uint b) noexcept;
-
-bool operator== (const QofInt128& a, const QofInt128& b) noexcept;
-bool operator!= (const QofInt128& a, const QofInt128& b) noexcept;
-bool operator<= (const QofInt128& a, const QofInt128& b) noexcept;
-bool operator>= (const QofInt128& a, const QofInt128& b) noexcept;
-bool operator< (const QofInt128& a, const QofInt128& b) noexcept;
-bool operator> (const QofInt128& a, const QofInt128& b) noexcept;
-
-std::ostream& operator<< (std::ostream&, const QofInt128&) noexcept;
+static const GncInt128 k_gncint128_Max {UINT64_MAX, UINT64_MAX, GncInt128::pos};
+static const GncInt128 k_gncint128_Min {UINT64_MAX, UINT64_MAX, GncInt128::neg};
+
+GncInt128 operator+ (GncInt128 a, const GncInt128& b) noexcept;
+GncInt128 operator- (GncInt128 a, const GncInt128& b) noexcept;
+GncInt128 operator* (GncInt128 a, const GncInt128& b) noexcept;
+GncInt128 operator/ (GncInt128 a, const GncInt128& b) noexcept;
+GncInt128 operator% (GncInt128 a, const GncInt128& b) noexcept;
+GncInt128 operator& (GncInt128 a, const GncInt128& b) noexcept;
+GncInt128 operator| (GncInt128 a, const GncInt128& b) noexcept;
+GncInt128 operator^ (GncInt128 a, const GncInt128& b) noexcept;
+GncInt128 operator<< (GncInt128 a, uint b) noexcept;
+GncInt128 operator>> (GncInt128 a, uint b) noexcept;
+
+bool operator== (const GncInt128& a, const GncInt128& b) noexcept;
+bool operator!= (const GncInt128& a, const GncInt128& b) noexcept;
+bool operator<= (const GncInt128& a, const GncInt128& b) noexcept;
+bool operator>= (const GncInt128& a, const GncInt128& b) noexcept;
+bool operator< (const GncInt128& a, const GncInt128& b) noexcept;
+bool operator> (const GncInt128& a, const GncInt128& b) noexcept;
+
+std::ostream& operator<< (std::ostream&, const GncInt128&) noexcept;
 
 /** Compute the greatest common denominator of two integers
  */
-QofInt128 gcd (int64_t a, int64_t b);
+GncInt128 gcd (int64_t a, int64_t b);
 
 /** Compute the least common multiple of two integers
  */
-QofInt128 lcm (int64_t a, int64_t b);
+GncInt128 lcm (int64_t a, int64_t b);
 
-#endif //QOFINT128_H
+#endif //GNCINT128_H
 
 /** @} */
diff --git a/src/libqof/qof/gnc-numeric.cpp b/src/libqof/qof/gnc-numeric.cpp
index 1fbfda8..94c0bd3 100644
--- a/src/libqof/qof/gnc-numeric.cpp
+++ b/src/libqof/qof/gnc-numeric.cpp
@@ -38,7 +38,6 @@ extern "C"
 #endif
 
 #include "gnc-numeric.h"
-#include "qofint128.hpp"
 #include "gnc-rational.hpp"
 
 using GncNumeric = GncRational;
diff --git a/src/libqof/qof/gnc-rational.cpp b/src/libqof/qof/gnc-rational.cpp
index d0d46e2..30e5cf4 100644
--- a/src/libqof/qof/gnc-rational.cpp
+++ b/src/libqof/qof/gnc-rational.cpp
@@ -47,7 +47,7 @@ GncRational::GncRational (gnc_numeric n) noexcept :
     }
 }
 
-GncRational::GncRational (QofInt128 num, QofInt128 den) noexcept :
+GncRational::GncRational (GncInt128 num, GncInt128 den) noexcept :
     m_num (num), m_den (den), m_error {}
 {
 }
@@ -121,7 +121,7 @@ GncRational::div (GncRational b, GncDenom& d) noexcept
     if (m_num.isBig() || m_den.isBig() ||
         b.m_num.isBig() || b.m_den.isBig())
     {
-        QofInt128 gcd = b.m_den.gcd(m_den);
+        GncInt128 gcd = b.m_den.gcd(m_den);
         b.m_den /= gcd;
         m_den /= gcd;
     }
@@ -141,7 +141,7 @@ GncRational::add (const GncRational& b, GncDenom& d) noexcept
             m_error = b.m_error;
         return *this;
     }
-    QofInt128 lcm = m_den.lcm (b.m_den);
+    GncInt128 lcm = m_den.lcm (b.m_den);
     m_num = m_num * lcm / m_den + b.m_num * lcm / b.m_den;
     m_den = lcm;
     round (d);
@@ -163,7 +163,7 @@ GncRational::round (GncDenom& denom) noexcept
         m_error = denom.m_error;
         return;
     }
-    QofInt128 new_den = denom.get();
+    GncInt128 new_den = denom.get();
     if (new_den == 0) new_den = m_den;
     if (!(m_num.isBig() || new_den.isBig() ))
     {
@@ -176,7 +176,7 @@ GncRational::round (GncDenom& denom) noexcept
             return;
         }
     }
-    QofInt128 new_num {}, remainder {};
+    GncInt128 new_num {}, remainder {};
     if (new_den.isNeg())
         m_num.div(-new_den * m_den, new_num, remainder);
     else
@@ -198,7 +198,7 @@ GncRational::round (GncDenom& denom) noexcept
         }
 
       /* First, try to reduce it */
-        QofInt128 gcd = new_num.gcd(new_den);
+        GncInt128 gcd = new_num.gcd(new_den);
         new_num /= gcd;
         new_den /= gcd;
         remainder /= gcd;
@@ -332,7 +332,7 @@ GncDenom::reduce (const GncRational& a) noexcept
         break;
 
     case DenomType::sigfigs:
-        QofInt128 val {};
+        GncInt128 val {};
         if (a.m_num.abs() > a.m_den)
             val = a.m_num.abs() / a.m_den;
         else
diff --git a/src/libqof/qof/gnc-rational.hpp b/src/libqof/qof/gnc-rational.hpp
index 09aeafa..0457c21 100644
--- a/src/libqof/qof/gnc-rational.hpp
+++ b/src/libqof/qof/gnc-rational.hpp
@@ -19,7 +19,7 @@
  * Boston, MA  02110-1301,  USA       gnu at gnu.org                   *
  *                                                                  *
  *******************************************************************/
-#include "qofint128.hpp"
+#include "gnc-int128.hpp"
 #include "gnc-numeric.h"
 
 struct GncDenom;
@@ -28,7 +28,7 @@ class GncRational
 {
 public:
     GncRational (gnc_numeric n) noexcept;
-    GncRational (QofInt128 num, QofInt128 den) noexcept;
+    GncRational (GncInt128 num, GncInt128 den) noexcept;
 /** Conversion operator; use static_cast<gnc_numeric>(foo). */
     operator gnc_numeric() const noexcept;
 /** Make a new GncRational with the opposite sign. */
@@ -46,8 +46,8 @@ public:
     GncRational& sub(const GncRational& b, GncDenom& d) noexcept;
 
 
-    QofInt128 m_num;
-    QofInt128 m_den;
+    GncInt128 m_num;
+    GncInt128 m_den;
     GNCNumericErrorCode m_error;
 };
 
@@ -55,7 +55,7 @@ struct GncDenom
 {
     GncDenom (GncRational& a, GncRational& b, int64_t spec, uint how) noexcept;
     void reduce (const GncRational& a) noexcept;
-    QofInt128 get () const noexcept { return m_value; }
+    GncInt128 get () const noexcept { return m_value; }
 
     enum class RoundType : int
     {
@@ -77,7 +77,7 @@ struct GncDenom
             sigfigs = GNC_HOW_DENOM_SIGFIG,
     };
 
-    QofInt128 m_value;
+    GncInt128 m_value;
     RoundType m_round;
     DenomType m_type;
     bool m_auto;
diff --git a/src/libqof/qof/test/Makefile.am b/src/libqof/qof/test/Makefile.am
index 0c0210f..e331b2e 100644
--- a/src/libqof/qof/test/Makefile.am
+++ b/src/libqof/qof/test/Makefile.am
@@ -34,20 +34,20 @@ check_PROGRAMS = \
 TESTS = ${check_PROGRAMS}
 
 if WITH_GOOGLE_TEST
-test_qofint128_SOURCES = \
-        $(top_srcdir)/${MODULEPATH}/qofint128.cpp \
+test_gnc_int128_SOURCES = \
+        $(top_srcdir)/${MODULEPATH}/gnc-int128.cpp \
         ${GTEST_ROOT}/src/gtest_main.cc \
-        gtest-qofint128.cpp
+        gtest-gnc-int128.cpp
 
-test_qofint128_CPPFLAGS = \
+test_gnc_int128_CPPFLAGS = \
         -I${GTEST_HEADERS} \
         ${GLIB_CFLAGS}
 
-test_qofint128_LDADD = \
+test_gnc_int128_LDADD = \
         ${GLIB_LIBS} \
         $(top_builddir)/src/test-core/libgtest.a
 
-check_PROGRAMS += test-qofint128
+check_PROGRAMS += test-gnc-int128
 endif
 
 test_qofdir = ${GNC_LIBEXECDIR}/${MODULEPATH}/test
diff --git a/src/libqof/qof/test/gtest-qofint128.cpp b/src/libqof/qof/test/gtest-gnc-int128.cpp
similarity index 69%
rename from src/libqof/qof/test/gtest-qofint128.cpp
rename to src/libqof/qof/test/gtest-gnc-int128.cpp
index 46ec5a5..b8a121e 100644
--- a/src/libqof/qof/test/gtest-qofint128.cpp
+++ b/src/libqof/qof/test/gtest-gnc-int128.cpp
@@ -1,5 +1,5 @@
 /********************************************************************
- * gtest-qofmath128.cpp -- unit tests for the QofInt128 class       *
+ * Gtest-gnc-int128.cpp -- unit tests for the GncInt128 class       *
  * Copyright (C) 2014 John Ralls <jralls at ceridwen.us>               *
  *                                                                  *
  * This program is free software; you can redistribute it and/or    *
@@ -22,11 +22,11 @@
  *******************************************************************/
 
 #include <gtest/gtest.h>
-#include "../qofint128.hpp"
+#include "../gnc-int128.hpp"
 
 TEST(qofint128_constructors, test_default_constructor)
 {
-    QofInt128 value {};
+    GncInt128 value {};
     EXPECT_EQ (true, value.isZero());
     EXPECT_EQ (false, value.isNeg());
     EXPECT_EQ (false, value.isBig());
@@ -36,28 +36,28 @@ TEST(qofint128_constructors, test_default_constructor)
 
 TEST(qofint128_constructors, test_single_arg_constructor)
 {
-    QofInt128 value1 (INT64_C(0));
+    GncInt128 value1 (INT64_C(0));
     EXPECT_EQ (true, value1.isZero());
     EXPECT_EQ (false, value1.isNeg());
     EXPECT_EQ (false, value1.isBig());
     EXPECT_EQ (false, value1.isOverflow());
     EXPECT_EQ (false, value1.isNan());
 
-    QofInt128 value2 (INT64_C(567894392130486208));
+    GncInt128 value2 (INT64_C(567894392130486208));
     EXPECT_EQ (false, value2.isZero());
     EXPECT_EQ (false, value2.isNeg());
     EXPECT_EQ (false, value2.isBig());
     EXPECT_EQ (false, value2.isOverflow());
     EXPECT_EQ (false, value2.isNan());
 
-    QofInt128 value3 (INT64_C(-567894392130486208));
+    GncInt128 value3 (INT64_C(-567894392130486208));
     EXPECT_EQ (false, value3.isZero());
     EXPECT_EQ (true, value3.isNeg());
     EXPECT_EQ (false, value3.isBig());
     EXPECT_EQ (false, value3.isOverflow());
     EXPECT_EQ (false, value3.isNan());
 
-    QofInt128 value4 (UINT64_C(13567894392130486208));
+    GncInt128 value4 (UINT64_C(13567894392130486208));
     EXPECT_EQ (false, value4.isZero());
     EXPECT_EQ (false, value4.isNeg());
     EXPECT_EQ (true, value4.isBig());
@@ -67,35 +67,35 @@ TEST(qofint128_constructors, test_single_arg_constructor)
 
 TEST(qofint128_constructors, test_double_arg_constructor)
 {
-    QofInt128 value1 (INT64_C(0), INT64_C(0));
+    GncInt128 value1 (INT64_C(0), INT64_C(0));
     EXPECT_EQ (true, value1.isZero());
     EXPECT_EQ (false, value1.isNeg());
     EXPECT_EQ (false, value1.isBig());
     EXPECT_EQ (false, value1.isOverflow());
     EXPECT_EQ (false, value1.isNan());
 
-    QofInt128 value2 (INT64_C(0), INT64_C(567894392130486208));
+    GncInt128 value2 (INT64_C(0), INT64_C(567894392130486208));
     EXPECT_EQ (false, value2.isZero());
     EXPECT_EQ (false, value2.isNeg());
     EXPECT_EQ (false, value2.isBig());
     EXPECT_EQ (false, value2.isOverflow());
     EXPECT_EQ (false, value2.isNan());
 
-    QofInt128 value3 (INT64_C(567894392130486208), INT64_C(0));
+    GncInt128 value3 (INT64_C(567894392130486208), INT64_C(0));
     EXPECT_EQ (false, value3.isZero());
     EXPECT_EQ (false, value3.isNeg());
     EXPECT_EQ (true, value3.isBig());
     EXPECT_EQ (false, value3.isOverflow());
     EXPECT_EQ (false, value3.isNan());
 
-    QofInt128 value4 (INT64_C(567894392130486208), INT64_C(567894392130486208));
+    GncInt128 value4 (INT64_C(567894392130486208), INT64_C(567894392130486208));
     EXPECT_EQ (false, value4.isZero());
     EXPECT_EQ (false, value4.isNeg());
     EXPECT_EQ (true, value4.isBig());
     EXPECT_EQ (false, value4.isOverflow());
     EXPECT_EQ (false, value4.isNan());
 
-    QofInt128 value5 (INT64_C(567894392130486208),
+    GncInt128 value5 (INT64_C(567894392130486208),
                       INT64_C(-567894392130486208));
     EXPECT_EQ (false, value5.isZero());
     EXPECT_EQ (false, value5.isNeg());
@@ -103,7 +103,7 @@ TEST(qofint128_constructors, test_double_arg_constructor)
     EXPECT_EQ (false, value5.isOverflow());
     EXPECT_EQ (false, value5.isNan());
 
-    QofInt128 value6 (INT64_C(-567894392130486208),
+    GncInt128 value6 (INT64_C(-567894392130486208),
                       INT64_C(567894392130486208));
     EXPECT_EQ (false, value6.isZero());
     EXPECT_EQ (true, value6.isNeg());
@@ -111,32 +111,32 @@ TEST(qofint128_constructors, test_double_arg_constructor)
     EXPECT_EQ (false, value6.isOverflow());
     EXPECT_EQ (false, value6.isNan());
 
-    QofInt128 value7 (UINT64_C(13567894392130486208),
-                      UINT64_C(13567894392130486208), QofInt128::pos);
+    GncInt128 value7 (UINT64_C(13567894392130486208),
+                      UINT64_C(13567894392130486208), GncInt128::pos);
     EXPECT_EQ (false, value7.isZero());
     EXPECT_EQ (false, value7.isNeg());
     EXPECT_EQ (true, value7.isBig());
     EXPECT_EQ (false, value7.isOverflow());
     EXPECT_EQ (false, value7.isNan());
 
-    QofInt128 value8 (UINT64_C(13567894392130486208),
-                      UINT64_C(13567894392130486208), QofInt128::neg);
+    GncInt128 value8 (UINT64_C(13567894392130486208),
+                      UINT64_C(13567894392130486208), GncInt128::neg);
     EXPECT_EQ (false, value8.isZero());
     EXPECT_EQ (true, value8.isNeg());
     EXPECT_EQ (true, value8.isBig());
     EXPECT_EQ (false, value8.isOverflow());
     EXPECT_EQ (false, value8.isNan());
 
-    QofInt128 value9 (UINT64_C(13567894392130486208),
-                      UINT64_C(13567894392130486208), QofInt128::overflow);
+    GncInt128 value9 (UINT64_C(13567894392130486208),
+                      UINT64_C(13567894392130486208), GncInt128::overflow);
     EXPECT_EQ (false, value9.isZero());
     EXPECT_EQ (false, value9.isNeg());
     EXPECT_EQ (true, value9.isBig());
     EXPECT_EQ (true, value9.isOverflow());
     EXPECT_EQ (false, value9.isNan());
 
-   QofInt128 value10 (UINT64_C(13567894392130486208),
-                      UINT64_C(13567894392130486208), QofInt128::NaN);
+   GncInt128 value10 (UINT64_C(13567894392130486208),
+                      UINT64_C(13567894392130486208), GncInt128::NaN);
     EXPECT_EQ (false, value10.isZero());
     EXPECT_EQ (false, value10.isNeg());
     EXPECT_EQ (true, value10.isBig());
@@ -149,45 +149,45 @@ TEST(qofint128_functions, test_int_functions)
     int64_t arg {INT64_C(567894392130486208)};
     int64_t narg {INT64_C(-567894392130486208)};
     uint64_t uarg {UINT64_C(13567894392130486208)};
-    QofInt128 value1 (INT64_C(0), arg);
+    GncInt128 value1 (INT64_C(0), arg);
     EXPECT_EQ (arg, static_cast<int64_t>(value1));
     EXPECT_EQ (static_cast<uint64_t>(arg), static_cast<uint64_t>(value1));
 
-    QofInt128 value2 (UINT64_C(0), uarg);
+    GncInt128 value2 (UINT64_C(0), uarg);
     EXPECT_THROW (static_cast<int64_t>(value2), std::overflow_error);
     EXPECT_EQ (uarg, static_cast<uint64_t>(value2));
 
-    QofInt128 value3 (UINT64_C(0), uarg, QofInt128::neg);
+    GncInt128 value3 (UINT64_C(0), uarg, GncInt128::neg);
     EXPECT_THROW (static_cast<int64_t>(value3), std::underflow_error);
     EXPECT_THROW (static_cast<uint64_t>(value3), std::underflow_error);
 
-    QofInt128 value4 (UINT64_C(0), uarg, QofInt128::overflow);
+    GncInt128 value4 (UINT64_C(0), uarg, GncInt128::overflow);
     EXPECT_THROW (static_cast<int64_t>(value4), std::overflow_error);
     EXPECT_THROW (static_cast<uint64_t>(value4), std::overflow_error);
 
-    QofInt128 value5 (UINT64_C(0), uarg, QofInt128::NaN);
+    GncInt128 value5 (UINT64_C(0), uarg, GncInt128::NaN);
     EXPECT_THROW (static_cast<int64_t>(value5), std::overflow_error);
     EXPECT_THROW (static_cast<uint64_t>(value5), std::overflow_error);
 
-    QofInt128 value6 (INT64_C(1), arg);
+    GncInt128 value6 (INT64_C(1), arg);
     EXPECT_THROW (static_cast<int64_t>(value6), std::overflow_error);
     EXPECT_EQ (arg + (UINT64_C(0x1) << 63), static_cast<uint64_t>(value6));
 
-    QofInt128 value7 (INT64_C(-1), arg);
+    GncInt128 value7 (INT64_C(-1), arg);
     EXPECT_EQ (-static_cast<int64_t>((UINT64_C(0x1) << 63) - arg),
                static_cast<int64_t>(value7));
     EXPECT_THROW (static_cast<uint64_t>(value7), std::underflow_error);
 
-    QofInt128 value8 (INT64_C(0), narg);
+    GncInt128 value8 (INT64_C(0), narg);
     EXPECT_EQ (narg, static_cast<int64_t>(value8));
     EXPECT_THROW (static_cast<uint64_t>(value8), std::underflow_error);
 
-    QofInt128 value9 (INT64_C(1), narg);
+    GncInt128 value9 (INT64_C(1), narg);
     EXPECT_EQ (static_cast<int64_t>((UINT64_C(0x1) << 63) + narg),
                static_cast<int64_t>(value9));
     EXPECT_EQ ((UINT64_C(0x1) << 63) + narg, static_cast<uint64_t>(value9));
 
-    QofInt128 value10 (INT64_C(-2), arg);
+    GncInt128 value10 (INT64_C(-2), arg);
     EXPECT_THROW (static_cast<int64_t>(value10), std::underflow_error);
     EXPECT_THROW (static_cast<uint64_t>(value10), std::underflow_error);
 
@@ -200,23 +200,23 @@ TEST(qofint128_functions, test_compare)
     int64_t sarg {INT64_C(567894392130486207)};
     int64_t nsarg {INT64_C(-567894392130486207)};
 
-    QofInt128 big (barg);
-    QofInt128 small (sarg);
-    QofInt128 neg_big (nbarg);
-    QofInt128 neg_small (nsarg);
+    GncInt128 big (barg);
+    GncInt128 small (sarg);
+    GncInt128 neg_big (nbarg);
+    GncInt128 neg_small (nsarg);
 
-    QofInt128 really_big (barg, sarg);
-    QofInt128 slightly_bigger (barg, barg);
-    QofInt128 not_as_big (sarg, barg);
-    QofInt128 a_little_smaller (sarg, sarg);
+    GncInt128 really_big (barg, sarg);
+    GncInt128 slightly_bigger (barg, barg);
+    GncInt128 not_as_big (sarg, barg);
+    GncInt128 a_little_smaller (sarg, sarg);
 
-    QofInt128 neg_really_big (barg, sarg, QofInt128::neg);
-    QofInt128 neg_slightly_bigger (barg, barg, QofInt128::neg);
-    QofInt128 neg_not_as_big (sarg, barg, QofInt128::neg);
-    QofInt128 neg_a_little_smaller (sarg, sarg, QofInt128::neg);
+    GncInt128 neg_really_big (barg, sarg, GncInt128::neg);
+    GncInt128 neg_slightly_bigger (barg, barg, GncInt128::neg);
+    GncInt128 neg_not_as_big (sarg, barg, GncInt128::neg);
+    GncInt128 neg_a_little_smaller (sarg, sarg, GncInt128::neg);
 
-    QofInt128 overflowed (INT64_C(0), INT64_C(0), QofInt128::overflow);
-    QofInt128 not_a_number (INT64_C(0), INT64_C(0), QofInt128::NaN);
+    GncInt128 overflowed (INT64_C(0), INT64_C(0), GncInt128::overflow);
+    GncInt128 not_a_number (INT64_C(0), INT64_C(0), GncInt128::NaN);
 
     EXPECT_EQ (-1, overflowed.cmp (big));
     EXPECT_EQ (-1, not_a_number.cmp (big));
@@ -250,9 +250,9 @@ TEST(qofint128_functions, test_compare)
     EXPECT_EQ (-1, neg_not_as_big.cmp(neg_a_little_smaller));
     EXPECT_EQ (-1, neg_really_big.cmp(neg_a_little_smaller));
 
-    EXPECT_EQ (0, neg_really_big.cmp(QofInt128(barg, sarg, QofInt128::neg)));
-    EXPECT_EQ (0, really_big.cmp(QofInt128(barg, sarg)));
-    EXPECT_EQ (0, really_big.cmp(QofInt128(barg, sarg,  QofInt128::pos)));
+    EXPECT_EQ (0, neg_really_big.cmp(GncInt128(barg, sarg, GncInt128::neg)));
+    EXPECT_EQ (0, really_big.cmp(GncInt128(barg, sarg)));
+    EXPECT_EQ (0, really_big.cmp(GncInt128(barg, sarg,  GncInt128::pos)));
 
     EXPECT_EQ (0, really_big.cmp(-neg_really_big));
     EXPECT_EQ (0, neg_really_big.cmp(-really_big));
@@ -264,15 +264,15 @@ TEST(qofint128_functions, stream_output)
     int64_t sarg {INT64_C(567894392130486207)};
     int64_t nsarg {INT64_C(-567894392130486207)};
 
-    QofInt128 small (sarg);
-    QofInt128 neg_small (nsarg);
+    GncInt128 small (sarg);
+    GncInt128 neg_small (nsarg);
 
-    QofInt128 really_big (barg, sarg);
-    QofInt128 neg_really_big (barg, sarg, QofInt128::neg);
+    GncInt128 really_big (barg, sarg);
+    GncInt128 neg_really_big (barg, sarg, GncInt128::neg);
 
-    QofInt128 overflowed (INT64_C(0), INT64_C(0), QofInt128::overflow);
-    QofInt128 not_a_number (INT64_C(0), INT64_C(0), QofInt128::NaN);
-    QofInt128 boundary_value (UINT64_C(1), UINT64_MAX);
+    GncInt128 overflowed (INT64_C(0), INT64_C(0), GncInt128::overflow);
+    GncInt128 not_a_number (INT64_C(0), INT64_C(0), GncInt128::NaN);
+    GncInt128 boundary_value (UINT64_C(1), UINT64_MAX);
 
     static const uint8_t char_buf_size {41};
     char buf[char_buf_size] {};
@@ -297,24 +297,24 @@ TEST(qofint128_functions, add_and_subtract)
     int64_t sarg {INT64_C(4344522355275710400)};
     uint64_t uarg {UINT64_C(13567894392130486208)};
 
-    QofInt128 smallest (sarg + 100);
-    QofInt128 smaller (barg + 500);
-    QofInt128 small (uarg);
-    QofInt128 big (sarg, barg);
-    QofInt128 bigger (static_cast<uint64_t>(barg), uarg);
-    QofInt128 biggest (uarg, static_cast<uint64_t>(barg));
-    QofInt128 nsmall (UINT64_C(0), uarg, QofInt128::neg);
+    GncInt128 smallest (sarg + 100);
+    GncInt128 smaller (barg + 500);
+    GncInt128 small (uarg);
+    GncInt128 big (sarg, barg);
+    GncInt128 bigger (static_cast<uint64_t>(barg), uarg);
+    GncInt128 biggest (uarg, static_cast<uint64_t>(barg));
+    GncInt128 nsmall (UINT64_C(0), uarg, GncInt128::neg);
 
-    EXPECT_EQ (QofInt128(INT64_C(2), INT64_C(499)), small += smaller);
-    EXPECT_EQ (QofInt128(INT64_C(2), INT64_C(499), QofInt128::neg),
+    EXPECT_EQ (GncInt128(INT64_C(2), INT64_C(499)), small += smaller);
+    EXPECT_EQ (GncInt128(INT64_C(2), INT64_C(499), GncInt128::neg),
                nsmall -= smaller);
 
-    EXPECT_EQ (QofInt128(uarg), small -= smaller);
-    EXPECT_EQ (QofInt128(static_cast<uint64_t>(barg + sarg/2), UINT64_MAX),
+    EXPECT_EQ (GncInt128(uarg), small -= smaller);
+    EXPECT_EQ (GncInt128(static_cast<uint64_t>(barg + sarg/2), UINT64_MAX),
                bigger += big);
-    EXPECT_EQ (QofInt128(static_cast<uint64_t>(barg), uarg), bigger -= big);
+    EXPECT_EQ (GncInt128(static_cast<uint64_t>(barg), uarg), bigger -= big);
     bigger += biggest;
-    EXPECT_EQ (QofInt128(UINT64_MAX, UINT64_MAX), bigger);
+    EXPECT_EQ (GncInt128(UINT64_MAX, UINT64_MAX), bigger);
     bigger += smallest;
     EXPECT_TRUE (bigger.isOverflow());
     bigger -= biggest;
@@ -327,17 +327,17 @@ TEST(qofint128_functions, multiply)
     int64_t sarg {INT64_C(4344522355275710400)};
     uint64_t uarg {UINT64_C(13567894392130486208)};
 
-    QofInt128 smallest (sarg);
-    QofInt128 smaller (barg);
-    QofInt128 small (uarg);
-    QofInt128 big (sarg, barg);
-    QofInt128 bigger (static_cast<uint64_t>(barg), uarg);
+    GncInt128 smallest (sarg);
+    GncInt128 smaller (barg);
+    GncInt128 small (uarg);
+    GncInt128 big (sarg, barg);
+    GncInt128 bigger (static_cast<uint64_t>(barg), uarg);
 
     small *= big;
     EXPECT_TRUE (small.isOverflow());
     big *= bigger;
     EXPECT_TRUE (big.isOverflow());
-    EXPECT_EQ (QofInt128(UINT64_C(1149052180967758316), UINT64_C(6323251814974894144)), smallest *= smaller);
+    EXPECT_EQ (GncInt128(UINT64_C(1149052180967758316), UINT64_C(6323251814974894144)), smallest *= smaller);
     EXPECT_FALSE (smallest.isOverflow());
 
 }
@@ -348,39 +348,39 @@ TEST(qofint128_functions, divide)
     int64_t sarg {INT64_C(4344522355275710400)};
     uint64_t uarg {UINT64_C(13567894392130486208)};
 
-    QofInt128 zero (INT64_C(0));
-    QofInt128 one (INT64_C(1));
-    QofInt128 two (INT64_C(2));
-    QofInt128 smallest (sarg);
-    QofInt128 smaller (barg);
-    QofInt128 small (uarg);
-    QofInt128 big (sarg, barg);
-    QofInt128 bigger (static_cast<uint64_t>(barg), uarg);
-    QofInt128 nsmall = -small;
-    QofInt128 nbig = -bigger;
-
-    EXPECT_EQ (QofInt128(INT64_C(0)), zero /= smallest);
-    EXPECT_EQ (QofInt128(INT64_C(0)), zero %= smallest);
+    GncInt128 zero (INT64_C(0));
+    GncInt128 one (INT64_C(1));
+    GncInt128 two (INT64_C(2));
+    GncInt128 smallest (sarg);
+    GncInt128 smaller (barg);
+    GncInt128 small (uarg);
+    GncInt128 big (sarg, barg);
+    GncInt128 bigger (static_cast<uint64_t>(barg), uarg);
+    GncInt128 nsmall = -small;
+    GncInt128 nbig = -bigger;
+
+    EXPECT_EQ (GncInt128(INT64_C(0)), zero /= smallest);
+    EXPECT_EQ (GncInt128(INT64_C(0)), zero %= smallest);
     smallest /= zero;
     EXPECT_TRUE (smallest.isNan());
 
-    QofInt128 r {}, q {};
+    GncInt128 r {}, q {};
 
     small.div (smaller, q, r);
     EXPECT_EQ (two, q);
-    EXPECT_EQ (QofInt128(INT64_C(3810195028972355394)), r);
+    EXPECT_EQ (GncInt128(INT64_C(3810195028972355394)), r);
 
     small.div (-smaller, q, r);
     EXPECT_EQ (-two, q);
-    EXPECT_EQ (QofInt128(INT64_C(3810195028972355394)), r);
+    EXPECT_EQ (GncInt128(INT64_C(3810195028972355394)), r);
 
     nsmall.div (smaller, q, r);
     EXPECT_EQ (-two, q);
-    EXPECT_EQ (QofInt128(INT64_C(3810195028972355394)), r);
+    EXPECT_EQ (GncInt128(INT64_C(3810195028972355394)), r);
 
     nsmall.div (-smaller, q, r);
     EXPECT_EQ (two, q);
-    EXPECT_EQ (QofInt128(INT64_C(3810195028972355394)), r);
+    EXPECT_EQ (GncInt128(INT64_C(3810195028972355394)), r);
 
     bigger.div (bigger, q, r);
     EXPECT_EQ (one, q);
@@ -391,27 +391,27 @@ TEST(qofint128_functions, divide)
     EXPECT_EQ (zero, r);
 
     big.div (smaller, q, r);
-    EXPECT_EQ (QofInt128(INT64_C(8213236443097627766)), q);
-    EXPECT_EQ (QofInt128(INT64_C(3162679692459777845)), r);
+    EXPECT_EQ (GncInt128(INT64_C(8213236443097627766)), q);
+    EXPECT_EQ (GncInt128(INT64_C(3162679692459777845)), r);
 
     bigger.div (big, q, r);
     EXPECT_EQ (two, q);
-    EXPECT_EQ (QofInt128(UINT64_C(534327326303355007),
+    EXPECT_EQ (GncInt128(UINT64_C(534327326303355007),
                          UINT64_C(3810195028972355394)), r);
 
     bigger.div (-big, q, r);
     EXPECT_EQ (-two, q);
-    EXPECT_EQ (QofInt128(UINT64_C(534327326303355007),
+    EXPECT_EQ (GncInt128(UINT64_C(534327326303355007),
                          UINT64_C(3810195028972355394)), r);
 
     nbig.div (-big, q, r);
     EXPECT_EQ (two, q);
-    EXPECT_EQ (QofInt128(UINT64_C(534327326303355007),
+    EXPECT_EQ (GncInt128(UINT64_C(534327326303355007),
                          UINT64_C(3810195028972355394)), r);
 
     nbig.div (-big, q, r);
     EXPECT_EQ (two, q);
-    EXPECT_EQ (QofInt128(UINT64_C(534327326303355007),
+    EXPECT_EQ (GncInt128(UINT64_C(534327326303355007),
                          UINT64_C(3810195028972355394)), r);
 
     big.div (bigger, q, r);
@@ -428,13 +428,13 @@ TEST(qofint128_functions, GCD)
     int64_t sarg {INT64_C(4344522355275710401)};
     uint64_t uarg {UINT64_C(13567894392130486208)};
 
-    QofInt128 one (INT64_C(1));
-    QofInt128 smallest (sarg);
-    QofInt128 smaller (barg);
-    QofInt128 small (uarg);
+    GncInt128 one (INT64_C(1));
+    GncInt128 smallest (sarg);
+    GncInt128 smaller (barg);
+    GncInt128 small (uarg);
 
-    QofInt128 big = smaller * smallest;
-    QofInt128 bigger = small * smaller;
+    GncInt128 big = smaller * smallest;
+    GncInt128 bigger = small * smaller;
 
     EXPECT_EQ (smaller, big.gcd(smaller));
     EXPECT_EQ (smallest, big.gcd(smallest));
@@ -450,17 +450,17 @@ TEST(qofint128_functions, pow)
 
     int64_t sarg {INT64_C(53309)};
     int64_t barg {INT64_C(4878849681579065407)};
-    QofInt128 little (sarg);
-    QofInt128 big (barg);
+    GncInt128 little (sarg);
+    GncInt128 big (barg);
     auto minus = -little;
 
-    EXPECT_EQ (QofInt128(1), little.pow(0));
-    EXPECT_EQ (QofInt128(0), QofInt128(0).pow(123));
+    EXPECT_EQ (GncInt128(1), little.pow(0));
+    EXPECT_EQ (GncInt128(0), GncInt128(0).pow(123));
     EXPECT_EQ (big * big, big.pow(2));
-    EXPECT_EQ (QofInt128(UINT64_C(66326033898754),
+    EXPECT_EQ (GncInt128(UINT64_C(66326033898754),
                          UINT64_C(10251549987585143605)), little.pow(7));
-    EXPECT_EQ (QofInt128(UINT64_C(66326033898754),
-                         UINT64_C(10251549987585143605), QofInt128::neg),
+    EXPECT_EQ (GncInt128(UINT64_C(66326033898754),
+                         UINT64_C(10251549987585143605), GncInt128::neg),
                minus.pow(7));
     auto over = minus.pow(9);
     EXPECT_TRUE(over.isOverflow());

commit d35bcdb877608b9dd44e7184f74c02189be1cd00
Author: John Ralls <jralls at ceridwen.us>
Date:   Fri Dec 5 14:50:23 2014 -0800

    Move arithmetic functions into C++ implementation.

diff --git a/src/libqof/qof/gnc-numeric.cpp b/src/libqof/qof/gnc-numeric.cpp
index cb3468b..1fbfda8 100644
--- a/src/libqof/qof/gnc-numeric.cpp
+++ b/src/libqof/qof/gnc-numeric.cpp
@@ -245,12 +245,8 @@ gnc_numeric_add(gnc_numeric a, gnc_numeric b,
     if (new_denom.m_error)
         return gnc_numeric_error (new_denom.m_error);
 
-    QofInt128 lcm = an.m_den.lcm (bn.m_den);
-    GncNumeric  result(an.m_num * lcm / an.m_den + bn.m_num * lcm / bn.m_den,
-                       lcm);
-    result.round (new_denom);
 
-    return static_cast<gnc_numeric>(result);
+    return static_cast<gnc_numeric>(an.add(bn, new_denom));
 }
 
 /* *******************************************************************
@@ -289,10 +285,8 @@ gnc_numeric_mul(gnc_numeric a, gnc_numeric b,
     GncDenom new_denom (an, bn, denom, how);
     if (new_denom.m_error)
         return gnc_numeric_error (new_denom.m_error);
-    GncNumeric  result(an.m_num * bn.m_num, an.m_den * bn.m_den);
-    result.round (new_denom);
 
-    return static_cast<gnc_numeric>(result);
+    return static_cast<gnc_numeric>(an.mul(bn, new_denom));
 }
 
 
@@ -314,33 +308,7 @@ gnc_numeric_div(gnc_numeric a, gnc_numeric b,
     if (new_denom.m_error)
         return gnc_numeric_error (new_denom.m_error);
 
-     if (bn.m_num.isNeg())
-    {
-        an.m_num = -an.m_num;
-        bn.m_num = -bn.m_num;
-    }
-
-   /* q = (a_num * b_den)/(b_num * a_den). If a_den == b_den they cancel out
-     * and it's just a_num/b_num.
-     */
-    if (an.m_den == bn.m_den)
-    {
-        GncNumeric q(an.m_num, bn.m_num);
-        q.round(new_denom);
-        return static_cast<gnc_numeric>(q);
-    }
-    /* Protect against possibly preventable overflow: */
-    if (an.m_num.isBig() || an.m_den.isBig() ||
-        bn.m_num.isBig() || bn.m_den.isBig())
-    {
-        QofInt128 gcd = bn.m_den.gcd(an.m_den);
-        bn.m_den /= gcd;
-        an.m_den /= gcd;
-    }
-
-    GncNumeric q(an.m_num * bn.m_den, bn.m_num * an.m_den);
-    q.round (new_denom);
-    return static_cast<gnc_numeric>(q);
+    return static_cast<gnc_numeric>(an.div(bn, new_denom));
 }
 
 /* *******************************************************************
diff --git a/src/libqof/qof/gnc-rational.cpp b/src/libqof/qof/gnc-rational.cpp
index efbdd67..d0d46e2 100644
--- a/src/libqof/qof/gnc-rational.cpp
+++ b/src/libqof/qof/gnc-rational.cpp
@@ -69,6 +69,91 @@ GncRational::operator gnc_numeric () const noexcept
     }
 }
 
+GncRational
+GncRational::operator-() const noexcept
+{
+    GncRational b(*this);
+    b.m_num = - b.m_num;
+    return b;
+}
+
+GncRational&
+GncRational::mul (const GncRational& b, GncDenom& d) noexcept
+{
+    if (m_error || b.m_error)
+    {
+        if (b.m_error)
+            m_error = b.m_error;
+        return *this;
+    }
+    m_num *= b.m_num;
+    m_den *= b.m_den;
+    round (d);
+    return *this;
+}
+
+GncRational&
+GncRational::div (GncRational b, GncDenom& d) noexcept
+{
+    if (m_error || b.m_error)
+    {
+        if (b.m_error)
+            m_error = b.m_error;
+        return *this;
+    }
+
+     if (b.m_num.isNeg())
+    {
+        m_num = -m_num;
+        b.m_num = -b.m_num;
+    }
+
+   /* q = (a_num * b_den)/(b_num * a_den). If a_den == b_den they cancel out
+     * and it's just a_num/b_num.
+     */
+    if (m_den == b.m_den)
+    {
+        m_den = b.m_num;
+        round(d);
+        return *this;
+    }
+    /* Protect against possibly preventable overflow: */
+    if (m_num.isBig() || m_den.isBig() ||
+        b.m_num.isBig() || b.m_den.isBig())
+    {
+        QofInt128 gcd = b.m_den.gcd(m_den);
+        b.m_den /= gcd;
+        m_den /= gcd;
+    }
+
+    m_num *= b.m_den;
+    m_den *= b.m_num;
+    round (d);
+    return *this;
+}
+
+GncRational&
+GncRational::add (const GncRational& b, GncDenom& d) noexcept
+{
+    if (m_error || b.m_error)
+    {
+        if (b.m_error)
+            m_error = b.m_error;
+        return *this;
+    }
+    QofInt128 lcm = m_den.lcm (b.m_den);
+    m_num = m_num * lcm / m_den + b.m_num * lcm / b.m_den;
+    m_den = lcm;
+    round (d);
+    return *this;
+}
+
+GncRational&
+GncRational::sub (const GncRational& b, GncDenom& d) noexcept
+{
+    return add(-b, d);
+}
+
 void
 GncRational::round (GncDenom& denom) noexcept
 {
diff --git a/src/libqof/qof/gnc-rational.hpp b/src/libqof/qof/gnc-rational.hpp
index 456d28c..09aeafa 100644
--- a/src/libqof/qof/gnc-rational.hpp
+++ b/src/libqof/qof/gnc-rational.hpp
@@ -29,12 +29,21 @@ class GncRational
 public:
     GncRational (gnc_numeric n) noexcept;
     GncRational (QofInt128 num, QofInt128 den) noexcept;
+/** Conversion operator; use static_cast<gnc_numeric>(foo). */
     operator gnc_numeric() const noexcept;
+/** Make a new GncRational with the opposite sign. */
+    GncRational operator-() const noexcept;
+/** Round/convert this to the denominator provided by d, according to d's
+ * m_round value.
+ */
     void round (GncDenom& d) noexcept;
-    GncRational& mul(const GncRational&, GncDenom& d) noexcept;
-    GncRational& div(const GncRational&, GncDenom& d) noexcept;
-    GncRational& add(const GncRational&, GncDenom& d) noexcept;
-    GncRational& sub(const GncRational&, GncDenom& d) noexcept;
+/* These are mutators; in other words, they implement the equivalent of
+ * operators *=, /=, +=, and -=. They return a reference to this for chaining.
+ */
+    GncRational& mul(const GncRational& b, GncDenom& d) noexcept;
+    GncRational& div(GncRational b, GncDenom& d) noexcept;
+    GncRational& add(const GncRational& b, GncDenom& d) noexcept;
+    GncRational& sub(const GncRational& b, GncDenom& d) noexcept;
 
 
     QofInt128 m_num;

commit 8e429f7458161cb60120d8ca9836cd59006a7323
Author: John Ralls <jralls at ceridwen.us>
Date:   Thu Dec 4 11:48:08 2014 -0800

    Rename GncNumeric to GncRational and move to its own files.

diff --git a/po/POTFILES.in b/po/POTFILES.in
index d0aaf53..4acbea6 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -430,6 +430,7 @@ src/import-export/qif-imp/gnc-plugin-qif-import.c
 [type: gettext/gsettings]src/import-export/qif-imp/gschemas/org.gnucash.dialogs.import.qif.gschema.xml.in.in
 src/libqof/qof/gnc-date.cpp
 src/libqof/qof/gnc-numeric.cpp
+src/libqof/qof/gnc-rational.cpp
 src/libqof/qof/guid.cpp
 src/libqof/qof/kvp_frame.cpp
 src/libqof/qof/kvp-util.cpp
diff --git a/src/libqof/qof/Makefile.am b/src/libqof/qof/Makefile.am
index a3a078b..0648195 100644
--- a/src/libqof/qof/Makefile.am
+++ b/src/libqof/qof/Makefile.am
@@ -25,6 +25,7 @@ AM_CPPFLAGS = \
 libgnc_qof_la_SOURCES =  \
    gnc-date.cpp        \
    gnc-numeric.cpp     \
+   gnc-rational.cpp    \
    guid.cpp            \
    kvp-util.cpp        \
    kvp_frame.cpp       \
@@ -51,6 +52,7 @@ qofinclude_HEADERS = \
    gnc-date-p.h      \
    gnc-date.h        \
    gnc-numeric.h     \
+   gnc-rational.hpp  \
    guid.h            \
    kvp-util-p.h      \
    kvp-util.h        \
diff --git a/src/libqof/qof/gnc-numeric.cpp b/src/libqof/qof/gnc-numeric.cpp
index 0a9c8b9..cb3468b 100644
--- a/src/libqof/qof/gnc-numeric.cpp
+++ b/src/libqof/qof/gnc-numeric.cpp
@@ -39,14 +39,16 @@ extern "C"
 
 #include "gnc-numeric.h"
 #include "qofint128.hpp"
+#include "gnc-rational.hpp"
+
+using GncNumeric = GncRational;
 
-/* static short module = MOD_ENGINE; */
 static const gint64 pten[] = { 1, 10, 100, 1000, 10000, 100000, 1000000,
 			       10000000, 100000000, 1000000000, 10000000000,
 			       100000000000, 1000000000000, 10000000000000,
 			       100000000000000, 10000000000000000,
 			       100000000000000000, 1000000000000000000};
-#define POWTEN_OVERFLOW -5
+static const int POWTEN_OVERFLOW {-5};
 
 static inline gint64
 powten (int exp)
@@ -55,281 +57,7 @@ powten (int exp)
 	return POWTEN_OVERFLOW;
     return exp < 0 ? -pten[-exp] : pten[exp];
 }
-struct GncNumeric; //Forward declaration
-
-struct GncDenom
-{
-    GncDenom (GncNumeric& a, GncNumeric& b, int64_t spec, uint how) noexcept;
-    void reduce (const GncNumeric& a) noexcept;
-    QofInt128 get () const noexcept { return m_value; }
-
-    enum class RoundType : int
-    {
-        floor = GNC_HOW_RND_FLOOR,
-            ceiling = GNC_HOW_RND_CEIL,
-            truncate = GNC_HOW_RND_TRUNC,
-            promote = GNC_HOW_RND_PROMOTE,
-            half_down = GNC_HOW_RND_ROUND_HALF_DOWN,
-            half_up = GNC_HOW_RND_ROUND_HALF_UP,
-            bankers = GNC_HOW_RND_ROUND,
-            never = GNC_HOW_RND_NEVER,
-    };
-    enum class DenomType : int
-    {
-        exact = GNC_HOW_DENOM_EXACT,
-            reduce = GNC_HOW_DENOM_REDUCE,
-            lcd = GNC_HOW_DENOM_LCD,
-            fixed = GNC_HOW_DENOM_FIXED,
-            sigfigs = GNC_HOW_DENOM_SIGFIG,
-    };
-
-    QofInt128 m_value;
-    RoundType m_round;
-    DenomType m_type;
-    bool m_auto;
-    uint m_sigfigs;
-    GNCNumericErrorCode m_error;
-};
-
-struct GncNumeric
-{
-    GncNumeric (gnc_numeric n) noexcept;
-    GncNumeric (QofInt128 num, QofInt128 den) noexcept;
-    operator gnc_numeric() const noexcept;
-    void round (GncDenom& denom) noexcept;
-
-    QofInt128 m_num;
-    QofInt128 m_den;
-    GNCNumericErrorCode m_error;
-};
-
-GncNumeric::GncNumeric (gnc_numeric n) noexcept :
-    m_num (n.num), m_den (n.denom), m_error {GNC_ERROR_OK}
-{
-    if (m_den.isNeg())
-    {
-          m_num *= -m_den;
-          m_den = 1;
-    }
-}
-
-GncNumeric::GncNumeric (QofInt128 num, QofInt128 den) noexcept :
-    m_num (num), m_den (den), m_error {}
-{
-}
-
-GncNumeric::operator gnc_numeric () const noexcept
-{
-    if (m_num.isOverflow() || m_num.isNan() ||
-        m_den.isOverflow() || m_den.isNan())
-        return gnc_numeric_error(GNC_ERROR_OVERFLOW);
-    if (m_error != GNC_ERROR_OK)
-        return gnc_numeric_error (m_error);
-    try
-    {
-        return {static_cast<int64_t>(m_num), static_cast<int64_t>(m_den)};
-    }
-    catch (std::overflow_error)
-    {
-        return gnc_numeric_error (GNC_ERROR_OVERFLOW);
-    }
-}
-
-void
-GncNumeric::round (GncDenom& denom) noexcept
-{
-    denom.reduce (*this);
-    if (m_error == GNC_ERROR_OK && denom.m_error != GNC_ERROR_OK)
-    {
-        m_error = denom.m_error;
-        return;
-    }
-    QofInt128 new_den = denom.get();
-    if (new_den == 0) new_den = m_den;
-    if (!(m_num.isBig() || new_den.isBig() ))
-    {
-        if (m_den == new_den)
-            return;
-
-        if (m_num.isZero())
-        {
-            m_den = new_den;
-            return;
-        }
-    }
-    QofInt128 new_num {}, remainder {};
-    if (new_den.isNeg())
-        m_num.div(-new_den * m_den, new_num, remainder);
-    else
-        (m_num * new_den).div(m_den, new_num, remainder);
-
-    if (remainder.isZero() && !(new_num.isBig() || new_den.isBig()))
-    {
-        m_num = new_num;
-        m_den = new_den;
-        return;
-    }
-
-    if (new_num.isBig() || new_den.isBig())
-    {
-        if (!denom.m_auto)
-        {
-            m_error = GNC_ERROR_OVERFLOW;
-            return;
-        }
 
-        /* First, try to reduce it */
-        QofInt128 gcd = new_num.gcd(new_den);
-        new_num /= gcd;
-        new_den /= gcd;
-        remainder /= gcd;
-
-/* if that didn't work, shift both num and den down until neither is "big", then
- * fall through to rounding.
- */
-        while (new_num && new_num.isBig() && new_den && new_den.isBig())
-        {
-            new_num >>= 1;
-            new_den >>= 1;
-            remainder >>= 1;
-        }
-    }
-
-/* If we got here, then we can't exactly represent the rational with
- * new_denom. We must either round or punt.
- */
-    switch (denom.m_round)
-    {
-    case GncDenom::RoundType::never:
-        m_error = GNC_ERROR_REMAINDER;
-        return;
-    case GncDenom::RoundType::floor:
-        if (new_num.isNeg()) ++new_num;
-        break;
-    case GncDenom::RoundType::ceiling:
-        if (! new_num.isNeg()) ++new_num;
-        break;
-    case GncDenom::RoundType::truncate:
-        break;
-    case GncDenom::RoundType::promote:
-        new_num += new_num.isNeg() ? -1 : 1;
-        break;
-    case GncDenom::RoundType::half_down:
-        if (new_den.isNeg())
-        {
-            if (remainder * 2 > m_den * new_den)
-                new_num += new_num.isNeg() ? -1 : 1;
-        }
-        else if (remainder * 2 > m_den)
-            new_num += new_num.isNeg() ? -1 : 1;
-        break;
-    case GncDenom::RoundType::half_up:
-        if (new_den.isNeg())
-        {
-            if (remainder * 2 >= m_den * new_den)
-                new_num += new_num.isNeg() ? -1 : 1;
-        }
-        else if (remainder * 2 >= m_den)
-            new_num += new_num.isNeg() ? -1 : 1;
-        break;
-    case GncDenom::RoundType::bankers:
-        if (new_den.isNeg())
-        {
-            if (remainder * 2 > m_den * -new_den ||
-                (remainder * 2 == m_den * -new_den && new_num % 2))
-                new_num += new_num.isNeg() ? -1 : 1;
-        }
-        else
-        {
-            if (remainder * 2 > m_den ||
-                (remainder * 2 == m_den && new_num % 2))
-                new_num += new_num.isNeg() ? -1 : 1;
-        }
-        break;
-    }
-    m_num = new_num;
-    m_den = new_den;
-    return;
-}
-
-GncDenom::GncDenom (GncNumeric& a, GncNumeric& b,
-                    int64_t spec, uint how) noexcept :
-    m_value (spec),
-    m_round (static_cast<GncDenom::RoundType>(how & GNC_NUMERIC_RND_MASK)),
-    m_type (static_cast<GncDenom::DenomType>(how & GNC_NUMERIC_DENOM_MASK)),
-    m_auto (spec == GNC_DENOM_AUTO),
-    m_sigfigs ((how & GNC_NUMERIC_SIGFIGS_MASK) >> 8),
-    m_error (GNC_ERROR_OK)
-
-{
-
-    if (!m_auto)
-        return;
-    switch (m_type)
-    {
-    case DenomType::fixed:
-        if (a.m_den == b.m_den)
-        {
-            m_value = a.m_den;
-        }
-        else if (b.m_num == 0)
-        {
-            m_value = a.m_den;
-            b.m_den = a.m_den;
-        }
-        else if (a.m_num == 0)
-        {
-            m_value = b.m_den;
-            a.m_den = b.m_den;
-        }
-        else
-        {
-            m_error = GNC_ERROR_DENOM_DIFF;
-        }
-        m_auto = false;
-        break;
-
-    case DenomType::lcd:
-        m_value = a.m_den.lcm(b.m_den);
-        m_auto = false;
-        break;
-    default:
-        break;
-
-    }
-}
-
-void
-GncDenom::reduce (const GncNumeric& a) noexcept
-{
-    if (!m_auto)
-        return;
-    switch (m_type)
-    {
-    default:
-        break;
-    case DenomType::reduce:
-        m_value = a.m_den / a.m_num.gcd(a.m_den);
-        break;
-
-    case DenomType::sigfigs:
-        QofInt128 val {};
-        if (a.m_num.abs() > a.m_den)
-            val = a.m_num.abs() / a.m_den;
-        else
-            val = a.m_den / a.m_num.abs();
-        uint digits {};
-        while (val >= 10)
-        {
-            ++digits;
-            val /= 10;
-        }
-        m_value = (a.m_num.abs() > a.m_den ? powten (m_sigfigs - digits - 1) :
-                   powten (m_sigfigs + digits));
-        m_auto = false;
-        break;
-    }
-}
 
 /* =============================================================== */
 /* This function is small, simple, and used everywhere below,
diff --git a/src/libqof/qof/gnc-rational.cpp b/src/libqof/qof/gnc-rational.cpp
new file mode 100644
index 0000000..efbdd67
--- /dev/null
+++ b/src/libqof/qof/gnc-rational.cpp
@@ -0,0 +1,266 @@
+/********************************************************************
+ * gnc-rational.hpp - A rational number library                     *
+ * Copyright 2014 John Ralls <jralls at ceridwen.us>                   *
+ * This program is free software; you can redistribute it and/or    *
+ * modify it under the terms of the GNU General Public License as   *
+ * published by the Free Software Foundation; either version 2 of   *
+ * the License, or (at your option) any later version.              *
+ *                                                                  *
+ * This program is distributed in the hope that it will be useful,  *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
+ * GNU General Public License for more details.                     *
+ *                                                                  *
+ * You should have received a copy of the GNU General Public License*
+ * along with this program; if not, contact:                        *
+ *                                                                  *
+ * Free Software Foundation           Voice:  +1-617-542-5942       *
+ * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
+ * Boston, MA  02110-1301,  USA       gnu at gnu.org                   *
+ *                                                                  *
+ *******************************************************************/
+
+#include "gnc-rational.hpp"
+
+static const gint64 pten[] = { 1, 10, 100, 1000, 10000, 100000, 1000000,
+			       10000000, 100000000, 1000000000, 10000000000,
+			       100000000000, 1000000000000, 10000000000000,
+			       100000000000000, 10000000000000000,
+			       100000000000000000, 1000000000000000000};
+static const int POWTEN_OVERFLOW {-5};
+
+static inline gint64
+powten (int exp)
+{
+    if (exp > 18 || exp < -18)
+	return POWTEN_OVERFLOW;
+    return exp < 0 ? -pten[-exp] : pten[exp];
+}
+
+GncRational::GncRational (gnc_numeric n) noexcept :
+    m_num (n.num), m_den (n.denom), m_error {GNC_ERROR_OK}
+{
+    if (m_den.isNeg())
+    {
+          m_num *= -m_den;
+          m_den = 1;
+    }
+}
+
+GncRational::GncRational (QofInt128 num, QofInt128 den) noexcept :
+    m_num (num), m_den (den), m_error {}
+{
+}
+
+GncRational::operator gnc_numeric () const noexcept
+{
+    if (m_num.isOverflow() || m_num.isNan() ||
+        m_den.isOverflow() || m_den.isNan())
+        return gnc_numeric_error(GNC_ERROR_OVERFLOW);
+    if (m_error != GNC_ERROR_OK)
+        return gnc_numeric_error (m_error);
+    try
+    {
+        return {static_cast<int64_t>(m_num), static_cast<int64_t>(m_den)};
+    }
+    catch (std::overflow_error)
+    {
+        return gnc_numeric_error (GNC_ERROR_OVERFLOW);
+    }
+}
+
+void
+GncRational::round (GncDenom& denom) noexcept
+{
+    denom.reduce (*this);
+    if (m_error == GNC_ERROR_OK && denom.m_error != GNC_ERROR_OK)
+    {
+        m_error = denom.m_error;
+        return;
+    }
+    QofInt128 new_den = denom.get();
+    if (new_den == 0) new_den = m_den;
+    if (!(m_num.isBig() || new_den.isBig() ))
+    {
+        if (m_den == new_den)
+            return;
+
+        if (m_num.isZero())
+        {
+            m_den = new_den;
+            return;
+        }
+    }
+    QofInt128 new_num {}, remainder {};
+    if (new_den.isNeg())
+        m_num.div(-new_den * m_den, new_num, remainder);
+    else
+        (m_num * new_den).div(m_den, new_num, remainder);
+
+    if (remainder.isZero() && !(new_num.isBig() || new_den.isBig()))
+    {
+        m_num = new_num;
+        m_den = new_den;
+        return;
+    }
+
+    if (new_num.isBig() || new_den.isBig())
+    {
+        if (!denom.m_auto)
+        {
+            m_error = GNC_ERROR_OVERFLOW;
+            return;
+        }
+
+      /* First, try to reduce it */
+        QofInt128 gcd = new_num.gcd(new_den);
+        new_num /= gcd;
+        new_den /= gcd;
+        remainder /= gcd;
+
+/* if that didn't work, shift both num and den down until neither is "big", th
+ * fall through to rounding.
+ */
+        while (new_num && new_num.isBig() && new_den && new_den.isBig())
+        {
+            new_num >>= 1;
+            new_den >>= 1;
+            remainder >>= 1;
+        }
+    }
+
+/* If we got here, then we can't exactly represent the rational with
+ * new_denom. We must either round or punt.
+ */
+    switch (denom.m_round)
+    {
+    case GncDenom::RoundType::never:
+        m_error = GNC_ERROR_REMAINDER;
+        return;
+    case GncDenom::RoundType::floor:
+        if (new_num.isNeg()) ++new_num;
+        break;
+    case GncDenom::RoundType::ceiling:
+        if (! new_num.isNeg()) ++new_num;
+        break;
+    case GncDenom::RoundType::truncate:
+        break;
+    case GncDenom::RoundType::promote:
+        new_num += new_num.isNeg() ? -1 : 1;
+        break;
+    case GncDenom::RoundType::half_down:
+        if (new_den.isNeg())
+        {
+            if (remainder * 2 > m_den * new_den)
+                new_num += new_num.isNeg() ? -1 : 1;
+        }
+        else if (remainder * 2 > m_den)
+            new_num += new_num.isNeg() ? -1 : 1;
+        break;
+    case GncDenom::RoundType::half_up:
+        if (new_den.isNeg())
+        {
+            if (remainder * 2 >= m_den * new_den)
+                new_num += new_num.isNeg() ? -1 : 1;
+        }
+        else if (remainder * 2 >= m_den)
+            new_num += new_num.isNeg() ? -1 : 1;
+        break;
+    case GncDenom::RoundType::bankers:
+        if (new_den.isNeg())
+        {
+            if (remainder * 2 > m_den * -new_den ||
+                (remainder * 2 == m_den * -new_den && new_num % 2))
+                new_num += new_num.isNeg() ? -1 : 1;
+        }
+        else
+        {
+            if (remainder * 2 > m_den ||
+                (remainder * 2 == m_den && new_num % 2))
+                new_num += new_num.isNeg() ? -1 : 1;
+        }
+        break;
+    }
+    m_num = new_num;
+    m_den = new_den;
+    return;
+}
+
+GncDenom::GncDenom (GncRational& a, GncRational& b,
+                    int64_t spec, uint how) noexcept :
+    m_value (spec),
+    m_round (static_cast<GncDenom::RoundType>(how & GNC_NUMERIC_RND_MASK)),
+    m_type (static_cast<GncDenom::DenomType>(how & GNC_NUMERIC_DENOM_MASK)),
+    m_auto (spec == GNC_DENOM_AUTO),
+    m_sigfigs ((how & GNC_NUMERIC_SIGFIGS_MASK) >> 8),
+    m_error (GNC_ERROR_OK)
+
+{
+
+    if (!m_auto)
+        return;
+    switch (m_type)
+    {
+    case DenomType::fixed:
+        if (a.m_den == b.m_den)
+        {
+            m_value = a.m_den;
+        }
+        else if (b.m_num == 0)
+        {
+            m_value = a.m_den;
+            b.m_den = a.m_den;
+        }
+        else if (a.m_num == 0)
+        {
+            m_value = b.m_den;
+            a.m_den = b.m_den;
+        }
+        else
+        {
+            m_error = GNC_ERROR_DENOM_DIFF;
+        }
+        m_auto = false;
+        break;
+
+    case DenomType::lcd:
+        m_value = a.m_den.lcm(b.m_den);
+        m_auto = false;
+        break;
+    default:
+        break;
+
+    }
+}
+
+void
+GncDenom::reduce (const GncRational& a) noexcept
+{
+    if (!m_auto)
+        return;
+    switch (m_type)
+    {
+    default:
+        break;
+    case DenomType::reduce:
+        m_value = a.m_den / a.m_num.gcd(a.m_den);
+        break;
+
+    case DenomType::sigfigs:
+        QofInt128 val {};
+        if (a.m_num.abs() > a.m_den)
+            val = a.m_num.abs() / a.m_den;
+        else
+            val = a.m_den / a.m_num.abs();
+        uint digits {};
+        while (val >= 10)
+        {
+            ++digits;
+            val /= 10;
+        }
+        m_value = (a.m_num.abs() > a.m_den ? powten (m_sigfigs - digits - 1) :
+                   powten (m_sigfigs + digits));
+        m_auto = false;
+        break;
+    }
+}
diff --git a/src/libqof/qof/gnc-rational.hpp b/src/libqof/qof/gnc-rational.hpp
new file mode 100644
index 0000000..456d28c
--- /dev/null
+++ b/src/libqof/qof/gnc-rational.hpp
@@ -0,0 +1,78 @@
+/********************************************************************
+ * gnc-rational.hpp - A rational number library                     *
+ * Copyright 2014 John Ralls <jralls at ceridwen.us>                   *
+ * This program is free software; you can redistribute it and/or    *
+ * modify it under the terms of the GNU General Public License as   *
+ * published by the Free Software Foundation; either version 2 of   *
+ * the License, or (at your option) any later version.              *
+ *                                                                  *
+ * This program is distributed in the hope that it will be useful,  *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
+ * GNU General Public License for more details.                     *
+ *                                                                  *
+ * You should have received a copy of the GNU General Public License*
+ * along with this program; if not, contact:                        *
+ *                                                                  *
+ * Free Software Foundation           Voice:  +1-617-542-5942       *
+ * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
+ * Boston, MA  02110-1301,  USA       gnu at gnu.org                   *
+ *                                                                  *
+ *******************************************************************/
+#include "qofint128.hpp"
+#include "gnc-numeric.h"
+
+struct GncDenom;
+
+class GncRational
+{
+public:
+    GncRational (gnc_numeric n) noexcept;
+    GncRational (QofInt128 num, QofInt128 den) noexcept;
+    operator gnc_numeric() const noexcept;
+    void round (GncDenom& d) noexcept;
+    GncRational& mul(const GncRational&, GncDenom& d) noexcept;
+    GncRational& div(const GncRational&, GncDenom& d) noexcept;
+    GncRational& add(const GncRational&, GncDenom& d) noexcept;
+    GncRational& sub(const GncRational&, GncDenom& d) noexcept;
+
+
+    QofInt128 m_num;
+    QofInt128 m_den;
+    GNCNumericErrorCode m_error;
+};
+
+struct GncDenom
+{
+    GncDenom (GncRational& a, GncRational& b, int64_t spec, uint how) noexcept;
+    void reduce (const GncRational& a) noexcept;
+    QofInt128 get () const noexcept { return m_value; }
+
+    enum class RoundType : int
+    {
+        floor = GNC_HOW_RND_FLOOR,
+            ceiling = GNC_HOW_RND_CEIL,
+            truncate = GNC_HOW_RND_TRUNC,
+            promote = GNC_HOW_RND_PROMOTE,
+            half_down = GNC_HOW_RND_ROUND_HALF_DOWN,
+            half_up = GNC_HOW_RND_ROUND_HALF_UP,
+            bankers = GNC_HOW_RND_ROUND,
+            never = GNC_HOW_RND_NEVER,
+    };
+    enum class DenomType : int
+    {
+        exact = GNC_HOW_DENOM_EXACT,
+            reduce = GNC_HOW_DENOM_REDUCE,
+            lcd = GNC_HOW_DENOM_LCD,
+            fixed = GNC_HOW_DENOM_FIXED,
+            sigfigs = GNC_HOW_DENOM_SIGFIG,
+    };
+
+    QofInt128 m_value;
+    RoundType m_round;
+    DenomType m_type;
+    bool m_auto;
+    uint m_sigfigs;
+    GNCNumericErrorCode m_error;
+};
+

commit 79938cae2e9d360a9cd39dfb0a5cc3d9113ce076
Author: John Ralls <jralls at ceridwen.us>
Date:   Wed Dec 3 16:32:01 2014 -0800

    Remove qofmath128, replaced by qofint128.

diff --git a/po/POTFILES.in b/po/POTFILES.in
index 3df8e25..d0aaf53 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -441,7 +441,7 @@ src/libqof/qof/qofevent.cpp
 src/libqof/qof/qofid.cpp
 src/libqof/qof/qofinstance.cpp
 src/libqof/qof/qoflog.cpp
-src/libqof/qof/qofmath128.cpp
+src/libqof/qof/qofint128.cpp
 src/libqof/qof/qofobject.cpp
 src/libqof/qof/qofquerycore.cpp
 src/libqof/qof/qofquery.cpp
diff --git a/src/libqof/qof/qofmath128-p.h b/src/libqof/qof/qofmath128-p.h
deleted file mode 100644
index 19d9174..0000000
--- a/src/libqof/qof/qofmath128-p.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/********************************************************************
- * qofmath128.h -- an 128-bit integer library                       *
- * Copyright (C) 2004 Linas Vepstas <linas at linas.org>               *
- *                                                                  *
- * This program is free software; you can redistribute it and/or    *
- * modify it under the terms of the GNU General Public License as   *
- * published by the Free Software Foundation; either version 2 of   *
- * the License, or (at your option) any later version.              *
- *                                                                  *
- * This program is distributed in the hope that it will be useful,  *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
- * GNU General Public License for more details.                     *
- *                                                                  *
- * You should have received a copy of the GNU General Public License*
- * along with this program; if not, contact:                        *
- *                                                                  *
- * Free Software Foundation           Voice:  +1-617-542-5942       *
- * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
- * Boston, MA  02110-1301,  USA       gnu at gnu.org                   *
- *                                                                  *
- *******************************************************************/
-
-#ifndef QOF_MATH_128_H
-#define QOF_MATH_128_H
-
-#include <glib.h>
-
-/** @addtogroup Math128
- *  Quick-n-dirty 128-bit integer math lib.   Things seem to mostly
- *  work, and have been tested, but not comprehensively tested.
- * @{
- */
-
-typedef struct
-{
-    guint64 hi;
-    guint64 lo;
-    short isneg;    /**< sign-bit -- T if number is negative */
-    short isbig;    /**< sizeflag -- T if number won't fit in signed 64-bit */
-} qofint128;
-
-/** Return true of two numbers are equal */
-gboolean equal128 (qofint128 a, qofint128 b);
-
-/** Return returns 1 if a>b, -1 if b>a, 0 if a == b */
-int cmp128 (qofint128 a, qofint128 b);
-
-/** Shift right by one bit (i.e. divide by two) */
-qofint128 shift128 (qofint128 x);
-
-/** Shift left by one bit (i.e. multiply by two) */
-qofint128 shiftleft128 (qofint128 x);
-
-/** Increment by one */
-qofint128 inc128 (qofint128 a);
-
-/** Add a pair of 128-bit numbers, returning a 128-bit number */
-qofint128 add128 (qofint128 a, qofint128 b);
-
-/** Multiply a pair of signed 64-bit numbers,
- *  returning a signed 128-bit number.
- */
-qofint128 mult128 (gint64 a, gint64 b);
-
-/** Divide a signed 128-bit number by a signed 64-bit,
- *  returning a signed 128-bit number.
- */
-qofint128 div128 (qofint128 n, gint64 d);
-
-/** Return the remainder of a signed 128-bit number modulo
- *  a signed 64-bit.  That is, return n%d in 128-bit math.
- *  I beleive that ths algo is overflow-free, but should be
- *  audited some more ...
- */
-gint64 rem128 (qofint128 n, gint64 d);
-
-/** Return the greatest common factor of two 64-bit numbers */
-guint64 gcf64(guint64 num, guint64 denom);
-
-/** Return the least common multiple of two 64-bit numbers. */
-qofint128 lcm128 (guint64 a, guint64 b);
-
-#endif
-
-/** @} */
diff --git a/src/libqof/qof/qofmath128.cpp b/src/libqof/qof/qofmath128.cpp
deleted file mode 100644
index daedc4f..0000000
--- a/src/libqof/qof/qofmath128.cpp
+++ /dev/null
@@ -1,418 +0,0 @@
-/********************************************************************
- * qofmath128.c -- an 128-bit integer library                       *
- * Copyright (C) 2004 Linas Vepstas <linas at linas.org>               *
- *                                                                  *
- * This program is free software; you can redistribute it and/or    *
- * modify it under the terms of the GNU General Public License as   *
- * published by the Free Software Foundation; either version 2 of   *
- * the License, or (at your option) any later version.              *
- *                                                                  *
- * This program is distributed in the hope that it will be useful,  *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
- * GNU General Public License for more details.                     *
- *                                                                  *
- * You should have received a copy of the GNU General Public License*
- * along with this program; if not, contact:                        *
- *                                                                  *
- * Free Software Foundation           Voice:  +1-617-542-5942       *
- * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
- * Boston, MA  02110-1301,  USA       gnu at gnu.org                   *
- *                                                                  *
- *******************************************************************/
-
-#include "config.h"
-#include "qofmath128-p.h"
-
-#include <glib.h>
-
-/* =============================================================== */
-/*
- *  Quick-n-dirty 128-bit integer math lib.   Things seem to mostly
- *  work, and have been tested, but not comprehensively tested.
- */
-
-#define HIBIT (0x8000000000000000ULL)
-
-/** Multiply a pair of signed 64-bit numbers,
- *  returning a signed 128-bit number.
- */
-qofint128
-mult128 (gint64 a, gint64 b)
-{
-    qofint128 prod;
-    guint64 a0, a1;
-    guint64 b0, b1;
-    guint64 d, d0, d1;
-    guint64 e, e0, e1;
-    guint64 f, f0, f1;
-    guint64 g, g0, g1;
-    guint64 sum, carry, roll, pmax;
-
-    prod.isneg = 0;
-    if (0 > a)
-    {
-        prod.isneg = !prod.isneg;
-        a = -a;
-    }
-
-    if (0 > b)
-    {
-        prod.isneg = !prod.isneg;
-        b = -b;
-    }
-
-    a1 = a >> 32;
-    a0 = a - (a1 << 32);
-
-    b1 = b >> 32;
-    b0 = b - (b1 << 32);
-
-    d = a0 * b0;
-    d1 = d >> 32;
-    d0 = d - (d1 << 32);
-
-    e = a0 * b1;
-    e1 = e >> 32;
-    e0 = e - (e1 << 32);
-
-    f = a1 * b0;
-    f1 = f >> 32;
-    f0 = f - (f1 << 32);
-
-    g = a1 * b1;
-    g1 = g >> 32;
-    g0 = g - (g1 << 32);
-
-    sum = d1 + e0 + f0;
-    carry = 0;
-    /* Can't say 1<<32 cause cpp will goof it up; 1ULL<<32 might work */
-    roll = 1 << 30;
-    roll <<= 2;
-
-    pmax = roll - 1;
-    while (pmax < sum)
-    {
-        sum -= roll;
-        carry ++;
-    }
-
-    prod.lo = d0 + (sum << 32);
-    prod.hi = carry + e1 + f1 + g0 + (g1 << 32);
-    // prod.isbig = (prod.hi || (sum >> 31));
-    prod.isbig = prod.hi || (prod.lo >> 63);
-
-    return prod;
-}
-
-/** Shift right by one bit (i.e. divide by two) */
-qofint128
-shift128 (qofint128 x)
-{
-    guint64 sbit = x.hi & 0x1;
-    x.hi >>= 1;
-    x.lo >>= 1;
-    x.isbig = 0;
-    if (sbit)
-    {
-        x.lo |= HIBIT;
-        x.isbig = 1;
-        return x;
-    }
-    if (x.hi)
-    {
-        x.isbig = 1;
-    }
-    return x;
-}
-
-/** Shift leftt by one bit (i.e. multiply by two) */
-qofint128
-shiftleft128 (qofint128 x)
-{
-    guint64 sbit;
-    sbit = x.lo & HIBIT;
-    x.hi <<= 1;
-    x.lo <<= 1;
-    x.isbig = 0;
-    if (sbit)
-    {
-        x.hi |= 1;
-        x.isbig = 1;
-        return x;
-    }
-    if (x.hi)
-    {
-        x.isbig = 1;
-    }
-    return x;
-}
-
-/** increment a 128-bit number by one */
-qofint128
-inc128 (qofint128 a)
-{
-    if (0 == a.isneg)
-    {
-        a.lo ++;
-        if (0 == a.lo)
-        {
-            a.hi ++;
-        }
-    }
-    else
-    {
-        if (0 == a.lo)
-        {
-            a.hi --;
-        }
-        a.lo --;
-    }
-
-    a.isbig = (a.hi != 0) || (a.lo >> 63);
-    return a;
-}
-
-/** Divide a signed 128-bit number by a signed 64-bit,
- *  returning a signed 128-bit number.
- */
-qofint128
-div128 (qofint128 n, gint64 d)
-{
-    qofint128 quotient;
-    int i;
-    guint64 remainder = 0;
-
-    quotient = n;
-    if (0 > d)
-    {
-        d = -d;
-        quotient.isneg = !quotient.isneg;
-    }
-
-    /* Use grade-school long division algorithm */
-    for (i = 0; i < 128; i++)
-    {
-        guint64 sbit = HIBIT & quotient.hi;
-        remainder <<= 1;
-        if (sbit) remainder |= 1;
-        quotient = shiftleft128 (quotient);
-        if (remainder >= static_cast<guint64>(d))
-        {
-            remainder -= d;
-            quotient.lo |= 1;
-        }
-    }
-
-    /* compute the carry situation */
-    quotient.isbig = (quotient.hi || (quotient.lo >> 63));
-
-    return quotient;
-}
-
-/** Return the remainder of a signed 128-bit number modulo
- *  a signed 64-bit.  That is, return n%d in 128-bit math.
- *  I beleive that ths algo is overflow-free, but should be
- *  audited some more ...
- */
-gint64
-rem128 (qofint128 n, gint64 d)
-{
-    qofint128 quotient = div128 (n, d);
-
-    qofint128 mu = mult128 (quotient.lo, d);
-
-    gint64 nn = 0x7fffffffffffffffULL & n.lo;
-    gint64 rr = 0x7fffffffffffffffULL & mu.lo;
-    return nn - rr;
-}
-
-/** Return true of two numbers are equal */
-gboolean
-equal128 (qofint128 a, qofint128 b)
-{
-    if (a.lo != b.lo) return 0;
-    if (a.hi != b.hi) return 0;
-    if (a.isneg != b.isneg) return 0;
-    return 1;
-}
-
-/** Return returns 1 if a>b, -1 if b>a, 0 if a == b */
-int
-cmp128 (qofint128 a, qofint128 b)
-{
-    if ((0 == a.isneg) && b.isneg) return 1;
-    if (a.isneg && (0 == b.isneg)) return -1;
-    if (0 == a.isneg)
-    {
-        if (a.hi > b.hi) return 1;
-        if (a.hi < b.hi) return -1;
-        if (a.lo > b.lo) return 1;
-        if (a.lo < b.lo) return -1;
-        return 0;
-    }
-
-    if (a.hi > b.hi) return -1;
-    if (a.hi < b.hi) return 1;
-    if (a.lo > b.lo) return -1;
-    if (a.lo < b.lo) return 1;
-    return 0;
-}
-
-/** Return the greatest common factor of two 64-bit numbers */
-guint64
-gcf64(guint64 num, guint64 denom)
-{
-    guint64   t;
-
-    t =  num % denom;
-    num = denom;
-    denom = t;
-
-    /* The strategy is to use Euclid's algorithm */
-    while (0 != denom)
-    {
-        t = num % denom;
-        num = denom;
-        denom = t;
-    }
-    /* num now holds the GCD (Greatest Common Divisor) */
-    return num;
-}
-
-/** Return the least common multiple of two 64-bit numbers. */
-qofint128
-lcm128 (guint64 a, guint64 b)
-{
-    guint64 gcf = gcf64 (a, b);
-    b /= gcf;
-    return mult128 (a, b);
-}
-
-/** Add a pair of 128-bit numbers, returning a 128-bit number */
-qofint128
-add128 (qofint128 a, qofint128 b)
-{
-    qofint128 sum;
-    if (a.isneg == b.isneg)
-    {
-        sum.isneg = a.isneg;
-        sum.hi = a.hi + b.hi;
-        sum.lo = a.lo + b.lo;
-        if ((sum.lo < a.lo) || (sum.lo < b.lo))
-        {
-            sum.hi ++;
-        }
-        sum.isbig = sum.hi || (sum.lo >> 63);
-        return sum;
-    }
-    if ((b.hi > a.hi) ||
-            ((b.hi == a.hi) && (b.lo > a.lo)))
-    {
-        qofint128 tmp = a;
-        a = b;
-        b = tmp;
-    }
-
-    sum.isneg = a.isneg;
-    sum.hi = a.hi - b.hi;
-    sum.lo = a.lo - b.lo;
-
-    if (sum.lo > a.lo)
-    {
-        sum.hi --;
-    }
-
-    sum.isbig = sum.hi || (sum.lo >> 63);
-    return sum;
-}
-
-
-#ifdef TEST_128_BIT_MULT
-
-static void pr (gint64 a, gint64 b)
-{
-    qofint128 prod = mult128 (a, b);
-    printf ("%" G_GINT64_FORMAT " * %" G_GINT64_FORMAT " = %"
-            G_GUINT64_FORMAT " %" G_GUINT64_FORMAT " (0x%"
-            G_GINT64_MODIFIER "x %" G_GINT64_MODIFIER "x) %hd\n",
-            a, b, prod.hi, prod.lo, prod.hi, prod.lo, prod.isbig);
-}
-
-static void prd (gint64 a, gint64 b, gint64 c)
-{
-    qofint128 prod = mult128 (a, b);
-    qofint128 quot = div128 (prod, c);
-    gint64 rem = rem128 (prod, c);
-    printf ("%" G_GINT64_FORMAT " * %" G_GINT64_FORMAT " / %" G_GINT64_FORMAT
-            " = %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT " + %"
-            G_GINT64_FORMAT " (0x%" G_GINT64_MODIFIER "x %"
-            G_GINT64_MODIFIER "x) %hd\n",
-            a, b, c, quot.hi, quot.lo, rem, quot.hi, quot.lo, quot.isbig);
-}
-
-int main ()
-{
-    gint64 x;
-    qofint128 n;
-    gint64 d;
-    qofint128 quot;
-    int i;
-
-    pr (2, 2);
-
-    x = 1 << 30;
-    x <<= 2;
-
-    pr (x, x);
-    pr (x + 1, x);
-    pr (x + 1, x + 1);
-
-    pr (x, -x);
-    pr (-x, -x);
-    pr (x - 1, x);
-    pr (x - 1, x - 1);
-    pr (x - 2, x - 2);
-
-    x <<= 1;
-    pr (x, x);
-    pr (x, -x);
-
-    pr (1000000, G_GINT64_CONSTANT(10000000000000));
-
-    prd (x, x, 2);
-    prd (x, x, 3);
-    prd (x, x, 4);
-    prd (x, x, 5);
-    prd (x, x, 6);
-
-    x <<= 29;
-    prd (3, x, 3);
-    prd (6, x, 3);
-    prd (99, x, 3);
-    prd (100, x, 5);
-    prd (540, x, 5);
-    prd (777, x, 7);
-    prd (1111, x, 11);
-
-    /* Really test division */
-    n.hi = 0xdd91;
-    n.lo = 0x6c5abefbb9e13480ULL;
-
-    d = 0x2ae79964d3ae1d04ULL;
-
-    for (i = 0; i < 20; i++)
-    {
-
-        quot = div128 (n, d);
-        printf ("%d result = %" G_GINT64_MODIFIER "x %" G_GINT64_MODIFIER "x\n",
-                i, quot.hi, quot.lo);
-        d >>= 1;
-        n = shift128 (n);
-    }
-    return 0;
-}
-
-#endif /* TEST_128_BIT_MULT */
-
-/* ======================== END OF FILE =================== */

commit 7c7946dec879e691aee8683ba85deda23b943f64
Author: John Ralls <jralls at ceridwen.us>
Date:   Wed Dec 3 10:31:37 2014 -0800

    Disable rescaling big GncNumerics when there is a pre-calculated auto denom.

diff --git a/src/libqof/qof/gnc-numeric.cpp b/src/libqof/qof/gnc-numeric.cpp
index a22d4f5..0a9c8b9 100644
--- a/src/libqof/qof/gnc-numeric.cpp
+++ b/src/libqof/qof/gnc-numeric.cpp
@@ -286,10 +286,12 @@ GncDenom::GncDenom (GncNumeric& a, GncNumeric& b,
         {
             m_error = GNC_ERROR_DENOM_DIFF;
         }
+        m_auto = false;
         break;
 
     case DenomType::lcd:
         m_value = a.m_den.lcm(b.m_den);
+        m_auto = false;
         break;
     default:
         break;
@@ -324,6 +326,8 @@ GncDenom::reduce (const GncNumeric& a) noexcept
         }
         m_value = (a.m_num.abs() > a.m_den ? powten (m_sigfigs - digits - 1) :
                    powten (m_sigfigs + digits));
+        m_auto = false;
+        break;
     }
 }
 

commit 503a607090980f5f14966b323a9a69878ed4a614
Author: John Ralls <jralls at ceridwen.us>
Date:   Wed Dec 3 10:29:55 2014 -0800

    More overflow-avoidance.
    
    One source of overflow during testing was changing the denominator on a
    max-precision number. If the numerator was clamped with a large denominator,
    changing to a smaller denominator without rescaling created a number that
    would overflow later when applied to a commodity with a different SCU. This
    change re-scales numerators in those cases so that the overflows don't happen.

diff --git a/src/engine/test-core/test-engine-stuff.c b/src/engine/test-core/test-engine-stuff.c
index 22da450..9a5ad6a 100644
--- a/src/engine/test-core/test-engine-stuff.c
+++ b/src/engine/test-core/test-engine-stuff.c
@@ -56,6 +56,8 @@ static gint total_num_accounts = 0;
 /* SCU == smallest currency unit -- the value of the denominator */
 static gint max_scu = 100; //6000;
 static gint min_scu = 100; //1;
+static const int64_t num_limit = INT64_MAX; //1E19+
+static const int64_t max_denom_mult = 1000000LL; //1E6
 
 
 /* The inverse fraction of split/transaction data that should
@@ -415,23 +417,23 @@ get_random_gnc_numeric(int64_t deno)
 
     if (deno == GNC_DENOM_AUTO)
     {
-    if (RAND_MAX / 8 > rand())
-    {
-        /* Random number between 1 and 6000 */
-        deno = RAND_IN_RANGE(6000ULL);
-    }
-    else
-    {
-        gint64 norm = RAND_IN_RANGE (11ULL);
-
-        /* multiple of 10, between 1 and 1 million */
-        deno = 1;
-        while (norm)
+        if (RAND_MAX / 8 > rand())
         {
-            deno *= 10;
-            norm --;
+            /* Random number between 1 and 6000 */
+            deno = RAND_IN_RANGE(6000ULL);
+        }
+        else
+        {
+            gint64 norm = RAND_IN_RANGE (11ULL);
+
+            /* multiple of 10, between 1 and 1 million */
+            deno = 1;
+            while (norm)
+            {
+                deno *= 10;
+                norm --;
+            }
         }
-    }
     }
     /* Make sure we have a non-zero denominator */
     if (0 == deno) deno = 1;
@@ -442,8 +444,6 @@ get_random_gnc_numeric(int64_t deno)
      * the numerator is clamped to the larger of num_limit / deno or num_limit /
      * max_denom_mult.
      */
-    static const int64_t num_limit = 1000000000000000000LL; //1E18
-    static const int64_t max_denom_mult = 1000000LL; //1E6
     const int64_t limit = num_limit / (max_denom_mult / deno == 0 ? max_denom_mult : max_denom_mult / deno);
     numer = get_random_gint64 ();
     if (numer > limit)
@@ -455,6 +455,7 @@ get_random_gnc_numeric(int64_t deno)
              numer = limit;
     }
     if (0 == numer) numer = 1;
+    g_log("test.engine.suff", G_LOG_LEVEL_INFO, "New GncNumeric %lld / %lld !\n", numer, deno);
     return gnc_numeric_create(numer, deno);
 }
 
@@ -908,15 +909,16 @@ static void
 add_random_splits(QofBook *book, Transaction *trn, GList *account_list)
 {
     Account *acc, *bcc;
-    Split *s;
+    Split *s1, *s2;
     gnc_numeric val;
+    int s2_scu;
 
     /* Gotta have at least two different accounts */
     if (1 >= g_list_length (account_list)) return;
 
     acc = get_random_list_element (account_list);
     xaccTransBeginEdit(trn);
-    s = get_random_split(book, acc, trn);
+    s1 = get_random_split(book, acc, trn);
 
     bcc = get_random_list_element (account_list);
     if ((bcc == acc) && (!do_bork()))
@@ -932,17 +934,25 @@ add_random_splits(QofBook *book, Transaction *trn, GList *account_list)
     }
 
     /* Set up two splits whose values really are opposites. */
-    val = xaccSplitGetValue(s);
-    s = get_random_split(book, bcc, trn);
+    val = xaccSplitGetValue(s1);
+    s2 = get_random_split(book, bcc, trn);
+    s2_scu = gnc_commodity_get_fraction (xaccAccountGetCommodity(s2->acc));
 
     /* Other split should have equal and opposite value */
     if (do_bork())
     {
         val = get_random_gnc_numeric(GNC_DENOM_AUTO);
+        g_log ("test.engine.suff", G_LOG_LEVEL_DEBUG, "Borking second %lld / %lld, scu %d\n", val.num, val.denom, s2_scu);
     }
     val = gnc_numeric_neg(val);
-    xaccSplitSetValue(s, val);
-    xaccSplitSetAmount(s, val);
+    xaccSplitSetValue(s2, val);
+    if (val.denom != s2_scu)
+    {
+        if (val.denom > s2_scu)
+            val.num /= val.denom / s2_scu;
+        val.denom = s2_scu;
+    }
+    xaccSplitSetAmount(s2, val);
     xaccTransCommitEdit(trn);
 }
 
@@ -1254,7 +1264,7 @@ Split*
 get_random_split(QofBook *book, Account *acct, Transaction *trn)
 {
     Split *ret;
-    gnc_numeric amt, val, rate;
+    gnc_numeric amt = {0, 1}, val = {0, 1}, rate = {0, 0};
     const gchar *str;
     gnc_commodity *com;
     int scu, denom;
@@ -1293,16 +1303,23 @@ get_random_split(QofBook *book, Account *acct, Transaction *trn)
  * be made too large by replacing the denominator with a smaller scu.
  */
         {
-            if (val.denom > scu && val.num / val.denom > (1LL << 63) / scu)
-                val.num /=  scu;
+            if (val.denom > scu && val.num > num_limit / (max_denom_mult / scu))
+            {
+                int64_t new_num = val.num / (val.denom / scu);
+                g_log("test.engine.suff", G_LOG_LEVEL_DEBUG, "Adjusting val.denom from %lld to %lld\n", val.num, new_num);
+                val.num = new_num;
+            }
             val.denom = scu;
         }
     }
     while (gnc_numeric_check(val) != GNC_ERROR_OK);
+    g_log ("test.engine.suff", G_LOG_LEVEL_DEBUG, "Random split value: %lld / %lld, scu %d\n", val.num, val.denom, scu);
     xaccSplitSetValue(ret, val);
 
     /* If the currencies are the same, the split amount should equal
      * the split value (unless we bork it on purpose) */
+    denom = gnc_commodity_get_fraction(xaccAccountGetCommodity(
+                                           xaccSplitGetAccount(ret)));
     if (gnc_commodity_equal (xaccTransGetCurrency(trn),
                              xaccAccountGetCommodity(acct)) &&
             (!do_bork()))
@@ -1311,8 +1328,6 @@ get_random_split(QofBook *book, Account *acct, Transaction *trn)
     }
     else
     {
-        denom = gnc_commodity_get_fraction(xaccAccountGetCommodity(
-                                               xaccSplitGetAccount(ret)));
         do
         {
             rate = get_random_rate ();
@@ -1320,7 +1335,10 @@ get_random_split(QofBook *book, Account *acct, Transaction *trn)
         }
         while (gnc_numeric_check(amt) != GNC_ERROR_OK);
     }
-    xaccSplitSetAmount(ret, amt);
+    g_log ("test.engine.suff", G_LOG_LEVEL_DEBUG, "Random split amount: %lld / %lld, rate %lld / %lld\n", amt.num, amt.denom, rate.num, rate.denom);
+
+
+     xaccSplitSetAmount(ret, amt);
 
     /* Make sure val and amt have the same sign. Note that amt is
        also allowed to be zero, because that is caused by a small

commit 456e121930903a14d5ca1076ae5e61c994c1744f
Author: John Ralls <jralls at ceridwen.us>
Date:   Wed Dec 3 10:24:37 2014 -0800

    Ensure random numeric denominator is the account SCU when creating splits.
    
    The lot creation and balancing code uses gnc_numeric_foo_fixed(), assuming that
    all amounts in a split have the same denominator, the account's SCU. Ensuring
    this when creating test cases prevents spurious failures.

diff --git a/src/app-utils/test/test-print-parse-amount.c b/src/app-utils/test/test-print-parse-amount.c
index c45f38d..5f7a4e6 100644
--- a/src/app-utils/test/test-print-parse-amount.c
+++ b/src/app-utils/test/test-print-parse-amount.c
@@ -115,7 +115,7 @@ run_tests (void)
         gnc_numeric n;
         gnc_numeric n1;
 
-        n = get_random_gnc_numeric ();
+        n = get_random_gnc_numeric (GNC_DENOM_AUTO);
         IS_VALID_NUM(n, n);
         test_num (n);
 
diff --git a/src/backend/xml/test/test-dom-converters1.c b/src/backend/xml/test/test-dom-converters1.c
index a64b000..ff47955 100644
--- a/src/backend/xml/test/test-dom-converters1.c
+++ b/src/backend/xml/test/test-dom-converters1.c
@@ -221,7 +221,7 @@ test_dom_tree_to_gnc_numeric(void)
     {
         gchar *message = NULL;
 
-        message = test_gnc_nums_internal(get_random_gnc_numeric());
+        message = test_gnc_nums_internal(get_random_gnc_numeric(GNC_DENOM_AUTO));
 
         do_test_args(message == NULL, "dom_tree_to_gnc_numeric",
                      __FILE__, __LINE__, message);
diff --git a/src/engine/test-core/test-engine-stuff.c b/src/engine/test-core/test-engine-stuff.c
index 60bd25e..22da450 100644
--- a/src/engine/test-core/test-engine-stuff.c
+++ b/src/engine/test-core/test-engine-stuff.c
@@ -289,7 +289,7 @@ get_random_kvp_value_depth (int type, gint depth)
         break;
 
     case KVP_TYPE_NUMERIC:
-        ret = kvp_value_new_gnc_numeric(get_random_gnc_numeric());
+        ret = kvp_value_new_gnc_numeric(get_random_gnc_numeric(GNC_DENOM_AUTO));
         break;
 
     case KVP_TYPE_STRING:
@@ -409,11 +409,12 @@ get_random_kvp_value(int type)
 #define RAND_IN_RANGE(X) (((X)*((gint64) (rand()+1)))/RAND_MAX)
 
 gnc_numeric
-get_random_gnc_numeric(void)
+get_random_gnc_numeric(int64_t deno)
 {
     gint64 numer;
-    gint64 deno;
 
+    if (deno == GNC_DENOM_AUTO)
+    {
     if (RAND_MAX / 8 > rand())
     {
         /* Random number between 1 and 6000 */
@@ -431,7 +432,7 @@ get_random_gnc_numeric(void)
             norm --;
         }
     }
-
+    }
     /* Make sure we have a non-zero denominator */
     if (0 == deno) deno = 1;
 
@@ -667,7 +668,7 @@ make_random_changes_to_price (QofBook *book, GNCPrice *p)
     gnc_price_set_typestr (p, string);
     g_free (string);
 
-    gnc_price_set_value (p, get_random_gnc_numeric ());
+    gnc_price_set_value (p, get_random_gnc_numeric (GNC_DENOM_AUTO));
 
     gnc_price_commit_edit (p);
 }
@@ -937,7 +938,7 @@ add_random_splits(QofBook *book, Transaction *trn, GList *account_list)
     /* Other split should have equal and opposite value */
     if (do_bork())
     {
-        val = get_random_gnc_numeric();
+        val = get_random_gnc_numeric(GNC_DENOM_AUTO);
     }
     val = gnc_numeric_neg(val);
     xaccSplitSetValue(s, val);
@@ -1283,7 +1284,7 @@ get_random_split(QofBook *book, Account *acct, Transaction *trn)
 
     do
     {
-        val = get_random_gnc_numeric ();
+        val = get_random_gnc_numeric (scu);
         if (val.num == 0)
             fprintf(stderr, "get_random_split: Created split with zero value: %p\n", ret);
 
@@ -1834,7 +1835,7 @@ get_random_query(void)
         case 11: /*  PR_PRICE */
             xaccQueryAddSharePriceMatch
             (q,
-             get_random_gnc_numeric (),
+             get_random_gnc_numeric (GNC_DENOM_AUTO),
              get_random_int_in_range (1, QOF_COMPARE_NEQ),
              get_random_queryop ());
             break;
@@ -1842,7 +1843,7 @@ get_random_query(void)
         case 12: /* PR_SHRS */
             xaccQueryAddSharesMatch
             (q,
-             get_random_gnc_numeric (),
+             get_random_gnc_numeric (GNC_DENOM_AUTO),
              get_random_int_in_range (1, QOF_COMPARE_NEQ),
              get_random_queryop ());
             break;
@@ -1850,7 +1851,7 @@ get_random_query(void)
         case 13: /* PR_VALUE */
             xaccQueryAddValueMatch
             (q,
-             get_random_gnc_numeric (),
+             get_random_gnc_numeric (GNC_DENOM_AUTO),
              get_random_int_in_range (1, QOF_NUMERIC_MATCH_ANY),
              get_random_int_in_range (1, QOF_COMPARE_NEQ),
              get_random_queryop ());
diff --git a/src/engine/test-core/test-engine-stuff.h b/src/engine/test-core/test-engine-stuff.h
index f4f20ec..707a744 100644
--- a/src/engine/test-core/test-engine-stuff.h
+++ b/src/engine/test-core/test-engine-stuff.h
@@ -28,7 +28,7 @@ typedef struct
 bin_data* get_random_binary_data(void);
 
 KvpFrame* get_random_kvp_frame(void);
-gnc_numeric get_random_gnc_numeric(void);
+gnc_numeric get_random_gnc_numeric(int64_t);
 GncGUID* get_random_guid(void);
 GList* get_random_glist(void);
 

commit b694df72020b43d63fce1d4bfa673e7ea9a42e43
Author: John Ralls <jralls at ceridwen.us>
Date:   Wed Dec 3 10:18:03 2014 -0800

    Prevent overflow.
    
    LCD denom was equivalent to using rounding.denom, which is val.denom * 10.
    If val.num was at the max # of digits that would overflow, so instead
    fix val.denom and actually round the result; since we're adding
    5/(val.denom * 10) to accomplish the rounding we want to truncate the result.

diff --git a/src/app-utils/gnc-ui-util.c b/src/app-utils/gnc-ui-util.c
index 668e1b4..73f3bd8 100644
--- a/src/app-utils/gnc-ui-util.c
+++ b/src/app-utils/gnc-ui-util.c
@@ -1258,8 +1258,8 @@ PrintAmountInternal(char *buf, gnc_numeric val, const GNCPrintAmountInfo *info)
     {
         rounding.num = 5; /* Limit the denom to 10^13 ~= 2^44, leaving max at ~524288 */
         rounding.denom = pow(10, max_dp + 1);
-        val = gnc_numeric_add(val, rounding, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
-        /* Yes, rounding up can cause overflow.  Check for it. */
+        val = gnc_numeric_add(val, rounding, val.denom, GNC_HOW_RND_TRUNC);
+
         if (gnc_numeric_check(val))
         {
             PWARN ("Bad numeric from rounding: %s.",

commit 701d8030b830a24089e0ae18d84bd2be8a032c32
Author: John Ralls <jralls at ceridwen.us>
Date:   Wed Dec 3 10:11:35 2014 -0800

    Ensure numeric errors aren't stored in split amounts or values.

diff --git a/src/engine/Split.c b/src/engine/Split.c
index 345d30a..d6d36f4 100644
--- a/src/engine/Split.c
+++ b/src/engine/Split.c
@@ -1265,10 +1265,13 @@ xaccSplitSetAmount (Split *s, gnc_numeric amt)
 
     xaccTransBeginEdit (s->parent);
     if (s->acc)
+    {
         s->amount = gnc_numeric_convert(amt, get_commodity_denom(s),
                                         GNC_HOW_RND_ROUND_HALF_UP);
+        g_assert (gnc_numeric_check (s->amount) == GNC_ERROR_OK);
+    }
     else
-        s->amount = amt;
+         s->amount = amt;
 
     SET_GAINS_ADIRTY(s);
     mark_split (s);
@@ -1283,6 +1286,7 @@ qofSplitSetValue (Split *split, gnc_numeric amt)
     g_return_if_fail(split);
     split->value = gnc_numeric_convert(amt,
                                        get_currency_denom(split), GNC_HOW_RND_ROUND_HALF_UP);
+    g_assert(gnc_numeric_check (split->value) != GNC_ERROR_OK);
 }
 
 /* The value of the split in the _transaction's_ currency. */
@@ -1300,7 +1304,8 @@ xaccSplitSetValue (Split *s, gnc_numeric amt)
     xaccTransBeginEdit (s->parent);
     new_val = gnc_numeric_convert(amt, get_currency_denom(s),
                                   GNC_HOW_RND_ROUND_HALF_UP);
-    if (gnc_numeric_check(new_val) == GNC_ERROR_OK)
+    if (gnc_numeric_check(new_val) == GNC_ERROR_OK &&
+        !(gnc_numeric_zero_p (new_val) && !gnc_numeric_zero_p (amt)))
         s->value = new_val;
     else PERR("numeric error %s in converting the split value's denominator with amount %s and denom  %d", gnc_numeric_errorCode_to_string(gnc_numeric_check(new_val)), gnc_numeric_to_string(amt), get_currency_denom(s));
 
diff --git a/src/engine/cap-gains.c b/src/engine/cap-gains.c
index a40d6ef..4003c67 100644
--- a/src/engine/cap-gains.c
+++ b/src/engine/cap-gains.c
@@ -338,6 +338,7 @@ xaccSplitAssignToLot (Split *split, GNCLot *lot)
         amt_tot = split->amount;
         amt_a = gnc_numeric_neg (baln);
         amt_b = gnc_numeric_sub_fixed (amt_tot, amt_a);
+        g_assert (gnc_numeric_check(amt_b) == GNC_ERROR_OK);
 
         PINFO ("++++++++++++++ splitting split=%p into amt = %s + %s",
                split,
@@ -377,6 +378,8 @@ xaccSplitAssignToLot (Split *split, GNCLot *lot)
                gnc_num_dbg_to_string(val_a),
                gnc_num_dbg_to_string(val_b) );
 
+        g_assert (!gnc_numeric_zero_p (amt_a));
+        g_assert (!gnc_numeric_zero_p (val_a));
         xaccSplitSetAmount (split, amt_a);
         xaccSplitSetValue (split, val_a);
 
diff --git a/src/engine/gnc-lot.c b/src/engine/gnc-lot.c
index f0c951a..876bd00 100644
--- a/src/engine/gnc-lot.c
+++ b/src/engine/gnc-lot.c
@@ -497,6 +497,7 @@ gnc_lot_get_balance (GNCLot *lot)
         Split *s = node->data;
         gnc_numeric amt = xaccSplitGetAmount (s);
         baln = gnc_numeric_add_fixed (baln, amt);
+        g_assert (gnc_numeric_check (baln) == GNC_ERROR_OK);
     }
 
     /* cache a zero balance as a closed lot */

commit c4d649bc93e83a44c346800211090202bf7b5e9f
Author: John Ralls <jralls at ceridwen.us>
Date:   Sat Nov 29 17:54:45 2014 -0800

    A better, clearer approach to constraining random gnc_numerics
    
    Which happens to actually work.

diff --git a/src/engine/test-core/test-engine-stuff.c b/src/engine/test-core/test-engine-stuff.c
index 16ddc4d..60bd25e 100644
--- a/src/engine/test-core/test-engine-stuff.c
+++ b/src/engine/test-core/test-engine-stuff.c
@@ -436,21 +436,22 @@ get_random_gnc_numeric(void)
     if (0 == deno) deno = 1;
 
     /* Arbitrary random numbers can cause pointless overflow during
-     * calculations.  Limit dynamic range to 1E18 because int64_t
-     * overflows before 1E19. The initial division is to help us down
-     * towards the range.  The loop is to "make sure" we get there.
-     * We might want to make this dependent on "deno" in the future.
+     * calculations, in particular the revaluing in xaccSplitSetValue where an
+     * input gnc_numeric is converted to use a new denominator. To prevent that,
+     * the numerator is clamped to the larger of num_limit / deno or num_limit /
+     * max_denom_mult.
      */
-    static const int64_t num_limit = 10000000000000LL; //1E14
+    static const int64_t num_limit = 1000000000000000000LL; //1E18
     static const int64_t max_denom_mult = 1000000LL; //1E6
+    const int64_t limit = num_limit / (max_denom_mult / deno == 0 ? max_denom_mult : max_denom_mult / deno);
     numer = get_random_gint64 ();
-    if (numer > num_limit * (deno > max_denom_mult ? max_denom_mult : deno))
+    if (numer > limit)
     {
-	int64_t num = numer % (num_limit * (deno > max_denom_mult ? max_denom_mult : deno));
+         int64_t num = numer % limit;
 	if (num)
 	    numer = num;
 	else
-	    numer = num_limit * (deno > max_denom_mult ? max_denom_mult : deno);
+             numer = limit;
     }
     if (0 == numer) numer = 1;
     return gnc_numeric_create(numer, deno);
@@ -1287,7 +1288,14 @@ get_random_split(QofBook *book, Account *acct, Transaction *trn)
             fprintf(stderr, "get_random_split: Created split with zero value: %p\n", ret);
 
         if (!do_bork())
+/* Another overflow-prevention measure. A numerator near the overflow limit can
+ * be made too large by replacing the denominator with a smaller scu.
+ */
+        {
+            if (val.denom > scu && val.num / val.denom > (1LL << 63) / scu)
+                val.num /=  scu;
             val.denom = scu;
+        }
     }
     while (gnc_numeric_check(val) != GNC_ERROR_OK);
     xaccSplitSetValue(ret, val);
@@ -1321,6 +1329,7 @@ get_random_split(QofBook *book, Account *acct, Transaction *trn)
     else
         g_assert(!gnc_numeric_positive_p(amt)); /* non-positive amt */
 
+//    g_assert(amt.num < (2LL << 56));
     qof_instance_set_slots(QOF_INSTANCE (ret), get_random_kvp_frame());
     xaccTransCommitEdit(trn);
 

commit 33a0c4e968c1564d1323b710e6c8c18776c1f83b
Author: John Ralls <jralls at ceridwen.us>
Date:   Sat Nov 29 17:53:41 2014 -0800

    Reimplement gnc_numeric with QofInt128
    
    And in a more C++ idiom.

diff --git a/src/engine/test/test-numeric.c b/src/engine/test/test-numeric.c
index 0cd2451..3abcdf1 100644
--- a/src/engine/test/test-numeric.c
+++ b/src/engine/test/test-numeric.c
@@ -153,21 +153,21 @@ check_reduce (void)
     check_unary_op (gnc_numeric_eq,
                     gnc_numeric_create (5011617, 167108327),
                     rval,
-                    val, "check_reduce(1) expected %s = %s = reduce(%s)");
+                    val, "check_reduce(1) expected %s got %s = reduce(%s)");
 
     val = gnc_numeric_create(17474724864LL, 136048896LL);
     rval = gnc_numeric_reduce (val);
     check_unary_op (gnc_numeric_eq,
                     gnc_numeric_create (4 * 17 * 17, 9),
                     rval,
-                    val, "check_reduce(2) expected %s = %s = reduce(%s)");
+                    val, "check_reduce(2) expected %s got %s = reduce(%s)");
 
     val = gnc_numeric_create(1024LL, 1099511627776LL);
     rval = gnc_numeric_reduce (val);
     check_unary_op (gnc_numeric_eq,
                     gnc_numeric_create (1, 1024 * 1024 * 1024),
                     rval,
-                    val, "check_reduce(3): expected %s = %s = reduce(%s)");
+                    val, "check_reduce(3): expected %s got %s = reduce(%s)");
 }
 
 /* ======================================================= */
@@ -235,7 +235,7 @@ check_equality_operator (void)
         bval = gnc_numeric_reduce (val);
         rval = gnc_numeric_reduce (mval);
         check_unary_op (gnc_numeric_eq,
-                        bval, rval, mval, "expected %s = %s = reduce(%s)");
+                        bval, rval, mval, "expected %s got %s = reduce(%s)");
 
         /* The unreduced versions should be equal */
         check_unary_op (gnc_numeric_equal,
@@ -277,56 +277,56 @@ check_rounding (void)
     check_unary_op (gnc_numeric_eq,
                     gnc_numeric_create (43, 100),
                     gnc_numeric_convert (val, 100, GNC_HOW_RND_FLOOR),
-                    val, "expected %s = %s = (%s as 100th's floor)");
+                    val, "expected %s got %s = (%s as 100th's floor)");
     check_unary_op (gnc_numeric_eq,
                     gnc_numeric_create (44, 100),
                     gnc_numeric_convert (val, 100, GNC_HOW_RND_CEIL),
-                    val, "expected %s = %s = (%s as 100th's ceiling)");
+                    val, "expected %s got %s = (%s as 100th's ceiling)");
     check_unary_op (gnc_numeric_eq,
                     gnc_numeric_create (43, 100),
                     gnc_numeric_convert (val, 100, GNC_HOW_RND_TRUNC),
-                    val, "expected %s = %s = (%s as 100th's trunc)");
+                    val, "expected %s got %s = (%s as 100th's trunc)");
     check_unary_op (gnc_numeric_eq,
                     gnc_numeric_create (44, 100),
                     gnc_numeric_convert (val, 100, GNC_HOW_RND_ROUND),
-                    val, "expected %s = %s = (%s as 100th's round)");
+                    val, "expected %s got %s = (%s as 100th's round)");
 
     val = gnc_numeric_create(1511, 1000);
     check_unary_op (gnc_numeric_eq,
                     gnc_numeric_create (151, 100),
                     gnc_numeric_convert (val, 100, GNC_HOW_RND_ROUND),
-                    val, "expected %s = %s = (%s as 100th's round)");
+                    val, "expected %s got %s = (%s as 100th's round)");
 
     val = gnc_numeric_create(1516, 1000);
     check_unary_op (gnc_numeric_eq,
                     gnc_numeric_create (152, 100),
                     gnc_numeric_convert (val, 100, GNC_HOW_RND_ROUND),
-                    val, "expected %s = %s = (%s as 100th's round)");
+                    val, "expected %s got %s = (%s as 100th's round)");
 
     /* Half-values always get rounded to nearest even number */
     val = gnc_numeric_create(1515, 1000);
     check_unary_op (gnc_numeric_eq,
                     gnc_numeric_create (152, 100),
                     gnc_numeric_convert (val, 100, GNC_HOW_RND_ROUND),
-                    val, "expected %s = %s = (%s as 100th's round)");
+                    val, "expected %s got %s = (%s as 100th's round)");
 
     val = gnc_numeric_create(1525, 1000);
     check_unary_op (gnc_numeric_eq,
                     gnc_numeric_create (152, 100),
                     gnc_numeric_convert (val, 100, GNC_HOW_RND_ROUND),
-                    val, "expected %s = %s = (%s as 100th's round)");
+                    val, "expected %s got %s = (%s as 100th's round)");
 
     val = gnc_numeric_create(1535, 1000);
     check_unary_op (gnc_numeric_eq,
                     gnc_numeric_create (154, 100),
                     gnc_numeric_convert (val, 100, GNC_HOW_RND_ROUND),
-                    val, "expected %s = %s = (%s as 100th's round)");
+                    val, "expected %s got %s = (%s as 100th's round)");
 
     val = gnc_numeric_create(1545, 1000);
     check_unary_op (gnc_numeric_eq,
                     gnc_numeric_create (154, 100),
                     gnc_numeric_convert (val, 100, GNC_HOW_RND_ROUND),
-                    val, "expected %s = %s = (%s as 100th's round)");
+                    val, "expected %s got %s = (%s as 100th's round)");
 }
 
 /* ======================================================= */
@@ -384,11 +384,11 @@ check_neg (void)
 
     check_unary_op (gnc_numeric_eq,
                     gnc_numeric_create (-2, 6), c,
-                    a, "expected %s = %s = -(%s)");
+                    a, "expected %s got %s = -(%s)");
 
     check_unary_op (gnc_numeric_eq,
                     gnc_numeric_create (-1, 4), d,
-                    b, "expected %s = %s = -(%s)");
+                    b, "expected %s got %s = -(%s)");
 
 }
 
@@ -546,6 +546,21 @@ check_add_subtract (void)
     }
 }
 
+static const gint64 pten[] = { 1, 10, 100, 1000, 10000, 100000, 1000000,
+			       10000000, 100000000, 1000000000, 10000000000,
+			       100000000000, 1000000000000, 10000000000000,
+			       100000000000000, 10000000000000000,
+			       100000000000000000, 1000000000000000000};
+#define POWTEN_OVERFLOW -5
+
+static inline gint64
+powten (int exp)
+{
+    if (exp > 18 || exp < -18)
+	return POWTEN_OVERFLOW;
+    return exp < 0 ? -pten[-exp] : pten[exp];
+}
+
 static void
 check_add_subtract_overflow (void)
 {
@@ -565,8 +580,8 @@ check_add_subtract_overflow (void)
 	gint64 bin_deno_a = (1 << exp_a);
 	gint64 bin_deno_b = (1 << exp_a);
 */
-	gint64 dec_deno_a = pwr64 (10, exp_a % 7);
-	gint64 dec_deno_b = pwr64 (10, exp_b % 7);
+	gint64 dec_deno_a = powten (exp_a % 7);
+	gint64 dec_deno_b = powten (exp_b % 7);
         gint64 na = get_random_gint64 () % (1000000 * dec_deno_a);
         gint64 nb = get_random_gint64 () % (1000000 * dec_deno_b);
 	gnc_numeric result;
@@ -808,9 +823,9 @@ check_mult_div (void)
      * an overflow error should be signalled; else the
      * divide routine should shift down the results till
      * the overflow is eliminated.
-     *
      */
-    check_binary_op (gnc_numeric_error (GNC_ERROR_OVERFLOW),
+/* Doesn't overflow any more! */
+    check_binary_op (gnc_numeric_error (GNC_ERROR_REMAINDER),
                      gnc_numeric_div(a, b, GNC_DENOM_AUTO,
                                      GNC_HOW_RND_NEVER | GNC_HOW_DENOM_EXACT),
                      a, b, "expected %s got %s = %s / %s for div exact");
@@ -869,7 +884,7 @@ check_mult_div (void)
     val_a = gnc_numeric_mul (frac, val_tot,
                              gnc_numeric_denom(val_tot),
                              GNC_HOW_RND_ROUND | GNC_HOW_DENOM_EXACT);
-    check_binary_op (gnc_numeric_create(562854125307LL, 100),
+    check_binary_op (gnc_numeric_create(562854124919LL, 100),
                      val_a, val_tot, frac,
                      "expected %s got %s = %s * %s for mult round");
 
@@ -897,7 +912,7 @@ check_reciprocal(void)
     check_unary_op (gnc_numeric_eq, gnc_numeric_create (-3, -1),
                     gnc_numeric_convert(val, GNC_DENOM_RECIPROCAL(1),
                                         GNC_HOW_RND_NEVER),
-                    val, "expected %s = %s = (%s as RECIP(1))");
+                    val, "expected %s got %s = (%s as RECIP(1))");
 
     a = gnc_numeric_create(200, 100);
     b = gnc_numeric_create(300, 100);
diff --git a/src/engine/test/utest-Split.cpp b/src/engine/test/utest-Split.cpp
index fa149b9..6048824 100644
--- a/src/engine/test/utest-Split.cpp
+++ b/src/engine/test/utest-Split.cpp
@@ -1683,6 +1683,7 @@ test_xaccSplitGetSharePrice (Fixture *fixture, gconstpointer pData)
     g_assert_cmpint (check.hits, ==, 0);
 
     /* Now invent some value/ammount pairs which cause numeric errors to test the limits */
+/* This one was supposed to overflow, but it doesn't any more.
     split->amount = gnc_numeric_create (987654321, 10);
     split->value = gnc_numeric_create (3, 789304166);
     quotient = gnc_numeric_div (split->value, split->amount,
@@ -1702,7 +1703,7 @@ test_xaccSplitGetSharePrice (Fixture *fixture, gconstpointer pData)
     g_assert (gnc_numeric_equal (result, expected));
     g_assert_cmpint (check.hits, ==, 2);
     g_free (check.msg);
-
+    */
     split->amount = gnc_numeric_create (987654321, 10);
     split->value = gnc_numeric_create (3, 0);
     quotient = gnc_numeric_div (split->value, split->amount,
@@ -1720,7 +1721,7 @@ test_xaccSplitGetSharePrice (Fixture *fixture, gconstpointer pData)
     expected = gnc_numeric_create (0, 1);
     result = xaccSplitGetSharePrice (split);
     g_assert (gnc_numeric_equal (result, expected));
-    g_assert_cmpint (check.hits, ==, 4);
+    g_assert_cmpint (check.hits, ==, 2);
     g_free (check.msg);
 
     split->amount = gnc_numeric_create (9, 0);
@@ -1740,7 +1741,7 @@ test_xaccSplitGetSharePrice (Fixture *fixture, gconstpointer pData)
     expected = gnc_numeric_create (0, 1);
     result = xaccSplitGetSharePrice (split);
     g_assert (gnc_numeric_equal (result, expected));
-    g_assert_cmpint (check.hits, ==, 6);
+    g_assert_cmpint (check.hits, ==, 4);
     g_free (check.msg);
 
     g_log_remove_handler (logdomain, hdlr);
diff --git a/src/engine/test/utest-Transaction.c b/src/engine/test/utest-Transaction.c
index 488dda6..6d9fa65 100644
--- a/src/engine/test/utest-Transaction.c
+++ b/src/engine/test/utest-Transaction.c
@@ -1262,7 +1262,7 @@ test_xaccTransGetAccountConvRate (Fixture *fixture, gconstpointer pData)
     g_assert_cmpint (check->hits, ==, 0);
     split1->value = gnc_numeric_zero();
     rate = xaccTransGetAccountConvRate (fixture->txn, fixture->acc1);
-    g_assert_cmpint (gnc_numeric_check (rate), ==, GNC_ERROR_ARG);
+    g_assert_cmpint (gnc_numeric_check (rate), ==, GNC_ERROR_OVERFLOW);
     g_assert_cmpint (check->hits, ==, 1);
 }
 /* xaccTransGetAccountBalance
diff --git a/src/libqof/qof/Makefile.am b/src/libqof/qof/Makefile.am
index fc2d065..a3a078b 100644
--- a/src/libqof/qof/Makefile.am
+++ b/src/libqof/qof/Makefile.am
@@ -36,6 +36,7 @@ libgnc_qof_la_SOURCES =  \
    qofevent.cpp        \
    qofid.cpp           \
    qofinstance.cpp     \
+   qofint128.cpp       \
    qoflog.cpp          \
    qofobject.cpp       \
    qofquery.cpp        \
@@ -79,7 +80,7 @@ noinst_HEADERS = \
    qofbook-p.h  \
    qofclass-p.h  \
    qofevent-p.h \
-   qofmath128-p.h  \
+   qofint128.hpp  \
    qofobject-p.h  \
    qofquery-p.h  \
    qofquerycore-p.h \
@@ -94,12 +95,4 @@ else
 EXTRA_DIST += qof-win32.cpp
 endif
 
-## For testing the qofmath128 routines
-# run "make check" (to build the test program) and then run test-qofmath
-check_PROGRAMS = test-qofmath
-test_qofmath_SOURCES = gnc-numeric.cpp
-test_qofmath_CPPFLAGS = $(AM_CPPFLAGS) -DTEST_128_BIT_MULT
-test_qofmath_LDFLAGS = $(libgnc_qof_la_LDFLAGS)
-test_qofmath_LDADD = $(libgnc_qof_common_libs)
-
 AM_CPPFLAGS += -DG_LOG_DOMAIN=\"qof\"
diff --git a/src/libqof/qof/gnc-numeric.cpp b/src/libqof/qof/gnc-numeric.cpp
index c1175b1..a22d4f5 100644
--- a/src/libqof/qof/gnc-numeric.cpp
+++ b/src/libqof/qof/gnc-numeric.cpp
@@ -38,12 +38,7 @@ extern "C"
 #endif
 
 #include "gnc-numeric.h"
-
-/* Note: The qofmath128 functions are used mostly here and almost
-         nowhere else. Hence, we inline the C code directly into here so
-         that the compiler can potentially inline the code as-is and speed
-         up the gnc-numeric.c functions. */
-#include "qofmath128.cpp"
+#include "qofint128.hpp"
 
 /* static short module = MOD_ENGINE; */
 static const gint64 pten[] = { 1, 10, 100, 1000, 10000, 100000, 1000000,
@@ -60,114 +55,304 @@ powten (int exp)
 	return POWTEN_OVERFLOW;
     return exp < 0 ? -pten[-exp] : pten[exp];
 }
+struct GncNumeric; //Forward declaration
 
-gint64
-pwr64 (gint64 op, int exp)
+struct GncDenom
+{
+    GncDenom (GncNumeric& a, GncNumeric& b, int64_t spec, uint how) noexcept;
+    void reduce (const GncNumeric& a) noexcept;
+    QofInt128 get () const noexcept { return m_value; }
+
+    enum class RoundType : int
+    {
+        floor = GNC_HOW_RND_FLOOR,
+            ceiling = GNC_HOW_RND_CEIL,
+            truncate = GNC_HOW_RND_TRUNC,
+            promote = GNC_HOW_RND_PROMOTE,
+            half_down = GNC_HOW_RND_ROUND_HALF_DOWN,
+            half_up = GNC_HOW_RND_ROUND_HALF_UP,
+            bankers = GNC_HOW_RND_ROUND,
+            never = GNC_HOW_RND_NEVER,
+    };
+    enum class DenomType : int
+    {
+        exact = GNC_HOW_DENOM_EXACT,
+            reduce = GNC_HOW_DENOM_REDUCE,
+            lcd = GNC_HOW_DENOM_LCD,
+            fixed = GNC_HOW_DENOM_FIXED,
+            sigfigs = GNC_HOW_DENOM_SIGFIG,
+    };
+
+    QofInt128 m_value;
+    RoundType m_round;
+    DenomType m_type;
+    bool m_auto;
+    uint m_sigfigs;
+    GNCNumericErrorCode m_error;
+};
+
+struct GncNumeric
+{
+    GncNumeric (gnc_numeric n) noexcept;
+    GncNumeric (QofInt128 num, QofInt128 den) noexcept;
+    operator gnc_numeric() const noexcept;
+    void round (GncDenom& denom) noexcept;
+
+    QofInt128 m_num;
+    QofInt128 m_den;
+    GNCNumericErrorCode m_error;
+};
+
+GncNumeric::GncNumeric (gnc_numeric n) noexcept :
+    m_num (n.num), m_den (n.denom), m_error {GNC_ERROR_OK}
 {
-    qofint128 tmp;
-    if (exp == 0) return 1;
-    if (exp % 2)
+    if (m_den.isNeg())
     {
-	tmp = mult128 (op, pwr64 (op, exp - 1));
-	if (tmp.isbig) return 0;
-	return tmp.lo;
+          m_num *= -m_den;
+          m_den = 1;
     }
-    tmp.lo = pwr64 (op, exp / 2);
-    tmp = mult128 (tmp.lo, tmp.lo);
-    if (tmp.isbig) return 0;
-    return tmp.lo;
 }
 
-/* =============================================================== */
-/* This function is small, simple, and used everywhere below,
- * lets try to inline it.
- */
-GNCNumericErrorCode
-gnc_numeric_check(gnc_numeric in)
+GncNumeric::GncNumeric (QofInt128 num, QofInt128 den) noexcept :
+    m_num (num), m_den (den), m_error {}
 {
-    if (G_LIKELY(in.denom != 0))
-    {
-        return GNC_ERROR_OK;
-    }
-    else if (in.num)
+}
+
+GncNumeric::operator gnc_numeric () const noexcept
+{
+    if (m_num.isOverflow() || m_num.isNan() ||
+        m_den.isOverflow() || m_den.isNan())
+        return gnc_numeric_error(GNC_ERROR_OVERFLOW);
+    if (m_error != GNC_ERROR_OK)
+        return gnc_numeric_error (m_error);
+    try
     {
-        if ((0 < in.num) || (-4 > in.num))
-        {
-            in.num = (gint64) GNC_ERROR_OVERFLOW;
-        }
-        return (GNCNumericErrorCode) in.num;
+        return {static_cast<int64_t>(m_num), static_cast<int64_t>(m_den)};
     }
-    else
+    catch (std::overflow_error)
     {
-        return GNC_ERROR_ARG;
+        return gnc_numeric_error (GNC_ERROR_OVERFLOW);
     }
 }
 
-/*
- *  Find the least common multiple of the denominators of a and b.
- */
-
-static inline gint64
-gnc_numeric_lcd(gnc_numeric a, gnc_numeric b)
+void
+GncNumeric::round (GncDenom& denom) noexcept
 {
-    qofint128 lcm;
-    if (gnc_numeric_check(a) || gnc_numeric_check(b))
+    denom.reduce (*this);
+    if (m_error == GNC_ERROR_OK && denom.m_error != GNC_ERROR_OK)
     {
-        return GNC_ERROR_ARG;
+        m_error = denom.m_error;
+        return;
     }
+    QofInt128 new_den = denom.get();
+    if (new_den == 0) new_den = m_den;
+    if (!(m_num.isBig() || new_den.isBig() ))
+    {
+        if (m_den == new_den)
+            return;
 
-    if (b.denom == a.denom) return a.denom;
+        if (m_num.isZero())
+        {
+            m_den = new_den;
+            return;
+        }
+    }
+    QofInt128 new_num {}, remainder {};
+    if (new_den.isNeg())
+        m_num.div(-new_den * m_den, new_num, remainder);
+    else
+        (m_num * new_den).div(m_den, new_num, remainder);
 
-    /* Special case: smaller divides smoothly into larger */
-    if ((b.denom < a.denom) && ((a.denom % b.denom) == 0))
+    if (remainder.isZero() && !(new_num.isBig() || new_den.isBig()))
     {
-        return a.denom;
+        m_num = new_num;
+        m_den = new_den;
+        return;
     }
-    if ((a.denom < b.denom) && ((b.denom % a.denom) == 0))
+
+    if (new_num.isBig() || new_den.isBig())
     {
-        return b.denom;
+        if (!denom.m_auto)
+        {
+            m_error = GNC_ERROR_OVERFLOW;
+            return;
+        }
+
+        /* First, try to reduce it */
+        QofInt128 gcd = new_num.gcd(new_den);
+        new_num /= gcd;
+        new_den /= gcd;
+        remainder /= gcd;
+
+/* if that didn't work, shift both num and den down until neither is "big", then
+ * fall through to rounding.
+ */
+        while (new_num && new_num.isBig() && new_den && new_den.isBig())
+        {
+            new_num >>= 1;
+            new_den >>= 1;
+            remainder >>= 1;
+        }
     }
 
-    lcm = lcm128 (a.denom, b.denom);
-    if (lcm.isbig) return GNC_ERROR_ARG;
-    return lcm.lo;
+/* If we got here, then we can't exactly represent the rational with
+ * new_denom. We must either round or punt.
+ */
+    switch (denom.m_round)
+    {
+    case GncDenom::RoundType::never:
+        m_error = GNC_ERROR_REMAINDER;
+        return;
+    case GncDenom::RoundType::floor:
+        if (new_num.isNeg()) ++new_num;
+        break;
+    case GncDenom::RoundType::ceiling:
+        if (! new_num.isNeg()) ++new_num;
+        break;
+    case GncDenom::RoundType::truncate:
+        break;
+    case GncDenom::RoundType::promote:
+        new_num += new_num.isNeg() ? -1 : 1;
+        break;
+    case GncDenom::RoundType::half_down:
+        if (new_den.isNeg())
+        {
+            if (remainder * 2 > m_den * new_den)
+                new_num += new_num.isNeg() ? -1 : 1;
+        }
+        else if (remainder * 2 > m_den)
+            new_num += new_num.isNeg() ? -1 : 1;
+        break;
+    case GncDenom::RoundType::half_up:
+        if (new_den.isNeg())
+        {
+            if (remainder * 2 >= m_den * new_den)
+                new_num += new_num.isNeg() ? -1 : 1;
+        }
+        else if (remainder * 2 >= m_den)
+            new_num += new_num.isNeg() ? -1 : 1;
+        break;
+    case GncDenom::RoundType::bankers:
+        if (new_den.isNeg())
+        {
+            if (remainder * 2 > m_den * -new_den ||
+                (remainder * 2 == m_den * -new_den && new_num % 2))
+                new_num += new_num.isNeg() ? -1 : 1;
+        }
+        else
+        {
+            if (remainder * 2 > m_den ||
+                (remainder * 2 == m_den && new_num % 2))
+                new_num += new_num.isNeg() ? -1 : 1;
+        }
+        break;
+    }
+    m_num = new_num;
+    m_den = new_den;
+    return;
 }
 
+GncDenom::GncDenom (GncNumeric& a, GncNumeric& b,
+                    int64_t spec, uint how) noexcept :
+    m_value (spec),
+    m_round (static_cast<GncDenom::RoundType>(how & GNC_NUMERIC_RND_MASK)),
+    m_type (static_cast<GncDenom::DenomType>(how & GNC_NUMERIC_DENOM_MASK)),
+    m_auto (spec == GNC_DENOM_AUTO),
+    m_sigfigs ((how & GNC_NUMERIC_SIGFIGS_MASK) >> 8),
+    m_error (GNC_ERROR_OK)
 
-/* Return the ratio n/d reduced so that there are no common factors. */
-static inline gnc_numeric
-reduce128(qofint128 n, gint64 d)
 {
-    gint64   t;
-    gint64   num;
-    gint64   denom;
-    gnc_numeric out;
-    qofint128 red;
 
-    t =  rem128 (n, d);
-    num = d;
-    denom = t;
+    if (!m_auto)
+        return;
+    switch (m_type)
+    {
+    case DenomType::fixed:
+        if (a.m_den == b.m_den)
+        {
+            m_value = a.m_den;
+        }
+        else if (b.m_num == 0)
+        {
+            m_value = a.m_den;
+            b.m_den = a.m_den;
+        }
+        else if (a.m_num == 0)
+        {
+            m_value = b.m_den;
+            a.m_den = b.m_den;
+        }
+        else
+        {
+            m_error = GNC_ERROR_DENOM_DIFF;
+        }
+        break;
+
+    case DenomType::lcd:
+        m_value = a.m_den.lcm(b.m_den);
+        break;
+    default:
+        break;
+
+    }
+}
 
-    /* The strategy is to use Euclid's algorithm */
-    while (denom > 0)
+void
+GncDenom::reduce (const GncNumeric& a) noexcept
+{
+    if (!m_auto)
+        return;
+    switch (m_type)
     {
-        t = num % denom;
-        num = denom;
-        denom = t;
+    default:
+        break;
+    case DenomType::reduce:
+        m_value = a.m_den / a.m_num.gcd(a.m_den);
+        break;
+
+    case DenomType::sigfigs:
+        QofInt128 val {};
+        if (a.m_num.abs() > a.m_den)
+            val = a.m_num.abs() / a.m_den;
+        else
+            val = a.m_den / a.m_num.abs();
+        uint digits {};
+        while (val >= 10)
+        {
+            ++digits;
+            val /= 10;
+        }
+        m_value = (a.m_num.abs() > a.m_den ? powten (m_sigfigs - digits - 1) :
+                   powten (m_sigfigs + digits));
     }
-    /* num now holds the GCD (Greatest Common Divisor) */
+}
 
-    red = div128 (n, num);
-    if (red.isbig)
+/* =============================================================== */
+/* This function is small, simple, and used everywhere below,
+ * lets try to inline it.
+ */
+GNCNumericErrorCode
+gnc_numeric_check(gnc_numeric in)
+{
+    if (G_LIKELY(in.denom != 0))
     {
-        return gnc_numeric_error (GNC_ERROR_OVERFLOW);
+        return GNC_ERROR_OK;
+    }
+    else if (in.num)
+    {
+        if ((0 < in.num) || (-4 > in.num))
+        {
+            in.num = (gint64) GNC_ERROR_OVERFLOW;
+        }
+        return (GNCNumericErrorCode) in.num;
+    }
+    else
+    {
+        return GNC_ERROR_ARG;
     }
-    out.num   = red.lo;
-    if (red.isneg) out.num = -out.num;
-    out.denom = d / num;
-    return out;
 }
 
+
 /* *******************************************************************
  *  gnc_numeric_zero_p
  ********************************************************************/
@@ -240,6 +425,7 @@ gnc_numeric_positive_p(gnc_numeric a)
     }
 }
 
+
 /* *******************************************************************
  *  gnc_numeric_compare
  *  returns 1 if a>b, -1 if b>a, 0 if a == b
@@ -249,7 +435,6 @@ int
 gnc_numeric_compare(gnc_numeric a, gnc_numeric b)
 {
     gint64 aa, bb;
-    qofint128 l, r;
 
     if (gnc_numeric_check(a) || gnc_numeric_check(b))
     {
@@ -263,28 +448,9 @@ gnc_numeric_compare(gnc_numeric a, gnc_numeric b)
         return -1;
     }
 
-    if  ((a.denom > 0) && (b.denom > 0))
-    {
-        /* Avoid overflows using 128-bit intermediate math */
-        l = mult128 (a.num, b.denom);
-        r = mult128 (b.num, a.denom);
-        return cmp128 (l, r);
-    }
-
-    if (a.denom < 0)
-        a.denom *= -1;
-    if (b.denom < 0)
-        b.denom *= -1;
-
-    /* BUG: Possible overflow here..  Also, doesn't properly deal with
-     * reciprocal denominators.
-     */
-    aa = a.num * a.denom;
-    bb = b.num * b.denom;
+    GncNumeric an (a), bn (b);
 
-    if (aa == bb) return 0;
-    if (aa > bb) return 1;
-    return -1;
+    return (an.m_num * bn.m_den).cmp(bn.m_num * an.m_den);
 }
 
 
@@ -306,50 +472,7 @@ gnc_numeric_eq(gnc_numeric a, gnc_numeric b)
 gboolean
 gnc_numeric_equal(gnc_numeric a, gnc_numeric b)
 {
-    qofint128 l, r;
-    if ((a.denom == b.denom) && (a.denom > 0))
-    {
-        return (a.num == b.num);
-    }
-    if ((a.denom > 0) && (b.denom > 0))
-    {
-        // return (a.num*b.denom == b.num*a.denom);
-        l = mult128 (a.num, b.denom);
-        r = mult128 (b.num, a.denom);
-        return equal128 (l, r);
-
-#if ALT_WAY_OF_CHECKING_EQUALITY
-        gnc_numeric ra = gnc_numeric_reduce (a);
-        gnc_numeric rb = gnc_numeric_reduce (b);
-        if (ra.denom != rb.denom) return 0;
-        if (ra.num != rb.num) return 0;
-        return 1;
-#endif
-    }
-    if ((a.denom < 0) && (b.denom < 0))
-    {
-        l = mult128 (a.num, -a.denom);
-        r = mult128 (b.num, -b.denom);
-        return equal128 (l, r);
-    }
-    else
-    {
-        /* BUG: One of the numbers has a reciprocal denom, and the other
-           does not. I just don't know to handle this case in any
-           reasonably overflow-proof yet simple way.  So, this function
-           will simply get it wrong whenever the three multiplies
-           overflow 64-bits.  -CAS */
-        if (a.denom < 0)
-        {
-            return ((a.num * -a.denom * b.denom) == b.num);
-        }
-        else
-        {
-            return (a.num == (b.num * a.denom * -b.denom));
-        }
-    }
-
-    return ((a.num * b.denom) == (a.denom * b.num));
+    return gnc_numeric_compare (a, b) == 0;
 }
 
 
@@ -372,7 +495,6 @@ gnc_numeric_same(gnc_numeric a, gnc_numeric b, gint64 denom,
 }
 
 
-
 /* *******************************************************************
  *  gnc_numeric_add
  ********************************************************************/
@@ -381,91 +503,22 @@ gnc_numeric
 gnc_numeric_add(gnc_numeric a, gnc_numeric b,
                 gint64 denom, gint how)
 {
-    gnc_numeric sum;
-
     if (gnc_numeric_check(a) || gnc_numeric_check(b))
     {
         return gnc_numeric_error(GNC_ERROR_ARG);
     }
 
-    if ((denom == GNC_DENOM_AUTO) &&
-            (how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_FIXED)
-    {
-        if (a.denom == b.denom)
-        {
-            denom = a.denom;
-        }
-        else if (b.num == 0)
-        {
-            denom = a.denom;
-            b.denom = a.denom;
-        }
-        else if (a.num == 0)
-        {
-            denom = b.denom;
-            a.denom = b.denom;
-        }
-        else
-        {
-            return gnc_numeric_error(GNC_ERROR_DENOM_DIFF);
-        }
-    }
-
-    if (a.denom < 0)
-    {
-        a.num *= -a.denom;  /* BUG: overflow not handled.  */
-        a.denom = 1;
-    }
+    GncNumeric an (a), bn (b);
+    GncDenom new_denom (an, bn, denom, how);
+    if (new_denom.m_error)
+        return gnc_numeric_error (new_denom.m_error);
 
-    if (b.denom < 0)
-    {
-        b.num *= -b.denom;  /* BUG: overflow not handled.  */
-        b.denom = 1;
-    }
+    QofInt128 lcm = an.m_den.lcm (bn.m_den);
+    GncNumeric  result(an.m_num * lcm / an.m_den + bn.m_num * lcm / bn.m_den,
+                       lcm);
+    result.round (new_denom);
 
-    /* Get an exact answer.. same denominator is the common case. */
-    if (a.denom == b.denom)
-    {
-        sum.num = a.num + b.num;  /* BUG: overflow not handled.  */
-        sum.denom = a.denom;
-    }
-    else
-    {
-        /* We want to do this:
-         *    sum.num = a.num*b.denom + b.num*a.denom;
-         *    sum.denom = a.denom*b.denom;
-         * but the multiply could overflow.
-         * Computing the LCD minimizes likelihood of overflow
-         */
-        gint64 lcd;
-        qofint128 ca, cb, cab;
-        lcd = gnc_numeric_lcd(a, b);
-        if (GNC_ERROR_ARG == lcd)
-        {
-            return gnc_numeric_error(GNC_ERROR_OVERFLOW);
-        }
-        ca = mult128 (a.num, lcd / a.denom);
-        if (ca.isbig) return gnc_numeric_error(GNC_ERROR_OVERFLOW);
-
-        cb = mult128 (b.num, lcd / b.denom);
-        if (cb.isbig) return gnc_numeric_error(GNC_ERROR_OVERFLOW);
-
-        cab = add128 (ca, cb);
-        if (cab.isbig) return gnc_numeric_error(GNC_ERROR_OVERFLOW);
-
-        sum.num   = cab.lo;
-        if (cab.isneg) sum.num = -sum.num;
-        sum.denom = lcd;
-    }
-
-    if ((denom == GNC_DENOM_AUTO) &&
-            ((how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_LCD))
-    {
-        denom = gnc_numeric_lcd(a, b);
-        how   = how & GNC_NUMERIC_RND_MASK;
-    }
-
-    return gnc_numeric_convert(sum, denom, how);
+    return static_cast<gnc_numeric>(result);
 }
 
 /* *******************************************************************
@@ -495,115 +548,19 @@ gnc_numeric
 gnc_numeric_mul(gnc_numeric a, gnc_numeric b,
                 gint64 denom, gint how)
 {
-    gnc_numeric product, result;
-    qofint128 bignume, bigdeno;
-
     if (gnc_numeric_check(a) || gnc_numeric_check(b))
     {
         return gnc_numeric_error(GNC_ERROR_ARG);
     }
 
-    if ((denom == GNC_DENOM_AUTO) &&
-            (how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_FIXED)
-    {
-        if (a.denom == b.denom)
-        {
-            denom = a.denom;
-        }
-        else if (b.num == 0)
-        {
-            denom = a.denom;
-        }
-        else if (a.num == 0)
-        {
-            denom = b.denom;
-        }
-        else
-        {
-            return gnc_numeric_error(GNC_ERROR_DENOM_DIFF);
-        }
-    }
-
-    if ((denom == GNC_DENOM_AUTO) &&
-            ((how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_LCD))
-    {
-        denom = gnc_numeric_lcd(a, b);
-        how   = how & GNC_NUMERIC_RND_MASK;
-    }
-
-    if (a.denom < 0)
-    {
-        a.num *= -a.denom;  /* BUG: overflow not handled.  */
-        a.denom = 1;
-    }
-
-    if (b.denom < 0)
-    {
-        b.num *= -b.denom;  /* BUG: overflow not handled.  */
-        b.denom = 1;
-    }
-
-    bignume = mult128 (a.num, b.num);
-    bigdeno = mult128 (a.denom, b.denom);
-    product.num   = a.num * b.num;
-    product.denom = a.denom * b.denom;
-
-    /* If it looks to be overflowing, try to reduce the fraction ... */
-    if (bignume.isbig || bigdeno.isbig)
-    {
-        gint64 tmp;
-        a = gnc_numeric_reduce (a);
-        b = gnc_numeric_reduce (b);
-        tmp = a.num;
-        a.num = b.num;
-        b.num = tmp;
-        a = gnc_numeric_reduce (a);
-        b = gnc_numeric_reduce (b);
-
-        bignume = mult128 (a.num, b.num);
-        bigdeno = mult128 (a.denom, b.denom);
-        product.num   = a.num * b.num;
-        product.denom = a.denom * b.denom;
-    }
-
-    /* If it its still overflowing, and rounding is allowed then round */
-    if (bignume.isbig || bigdeno.isbig)
-    {
-        /* If rounding allowed, then shift until there's no
-         * more overflow. The conversion at the end will fix
-         * things up for the final value. Else overflow. */
-        if ((how & GNC_NUMERIC_RND_MASK) == GNC_HOW_RND_NEVER)
-        {
-            if (bigdeno.isbig)
-            {
-                return gnc_numeric_error (GNC_ERROR_OVERFLOW);
-            }
-            product = reduce128 (bignume, product.denom);
-            if (gnc_numeric_check (product))
-            {
-                return gnc_numeric_error (GNC_ERROR_OVERFLOW);
-            }
-        }
-        else
-        {
-            while (bignume.isbig || bigdeno.isbig)
-            {
-                bignume = shift128 (bignume);
-                bigdeno = shift128 (bigdeno);
-            }
-            product.num = bignume.lo;
-            if (bignume.isneg) product.num = -product.num;
-
-            product.denom = bigdeno.lo;
-            if (0 == product.denom)
-            {
-                return gnc_numeric_error (GNC_ERROR_OVERFLOW);
-            }
-        }
-    }
+    GncNumeric an (a), bn (b);
+    GncDenom new_denom (an, bn, denom, how);
+    if (new_denom.m_error)
+        return gnc_numeric_error (new_denom.m_error);
+    GncNumeric  result(an.m_num * bn.m_num, an.m_den * bn.m_den);
+    result.round (new_denom);
 
-    result = gnc_numeric_convert(product, denom, how);
-    return result;
+    return static_cast<gnc_numeric>(result);
 }
 
 
@@ -615,128 +572,43 @@ gnc_numeric
 gnc_numeric_div(gnc_numeric a, gnc_numeric b,
                 gint64 denom, gint how)
 {
-    gnc_numeric quotient;
-    qofint128 nume, deno;
-
     if (gnc_numeric_check(a) || gnc_numeric_check(b))
     {
         return gnc_numeric_error(GNC_ERROR_ARG);
     }
 
-    if ((denom == GNC_DENOM_AUTO) &&
-            (how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_FIXED)
-    {
-        if (a.denom == b.denom)
-        {
-            denom = a.denom;
-        }
-        else if (a.denom == 0)
-        {
-            denom = b.denom;
-        }
-        else
-        {
-            return gnc_numeric_error(GNC_ERROR_DENOM_DIFF);
-        }
-    }
-
-
-    if (a.denom < 0)
-    {
-        a.num *= -a.denom;   /* BUG: overflow not handled.  */
-        a.denom = 1;
-    }
-
-    if (b.denom < 0)
-    {
-        b.num *= -b.denom;   /* BUG: overflow not handled.  */
-        b.denom = 1;
-    }
+    GncNumeric an (a), bn (b);
+    GncDenom new_denom (an, bn, denom, how);
+    if (new_denom.m_error)
+        return gnc_numeric_error (new_denom.m_error);
 
-    if (a.denom == b.denom)
+     if (bn.m_num.isNeg())
     {
-        quotient.num = a.num;
-        quotient.denom = b.num;
+        an.m_num = -an.m_num;
+        bn.m_num = -bn.m_num;
     }
-    else
-    {
-        gint64 sgn = 1;
-        if (0 > a.num)
-        {
-            sgn = -sgn;
-            a.num = -a.num;
-        }
-        if (0 > b.num)
-        {
-            sgn = -sgn;
-            b.num = -b.num;
-        }
-        nume = mult128(a.num, b.denom);
-        deno = mult128(b.num, a.denom);
-
-        /* Try to avoid overflow by removing common factors */
-        if (nume.isbig && deno.isbig)
-        {
-            gnc_numeric ra = gnc_numeric_reduce (a);
-            gnc_numeric rb = gnc_numeric_reduce (b);
 
-            gint64 gcf_nume = gcf64(ra.num, rb.num);
-            gint64 gcf_deno = gcf64(rb.denom, ra.denom);
-            nume = mult128(ra.num / gcf_nume, rb.denom / gcf_deno);
-            deno = mult128(rb.num / gcf_nume, ra.denom / gcf_deno);
-        }
-
-        if ((0 == nume.isbig) && (0 == deno.isbig))
-        {
-            quotient.num = sgn * nume.lo;
-            quotient.denom = deno.lo;
-            goto dive_done;
-        }
-        else if (0 == deno.isbig)
-        {
-            quotient = reduce128 (nume, deno.lo);
-            if (0 == gnc_numeric_check (quotient))
-            {
-                quotient.num *= sgn;
-                goto dive_done;
-            }
-        }
-
-        /* If rounding allowed, then shift until there's no
-         * more overflow. The conversion at the end will fix
-         * things up for the final value. */
-        if ((how & GNC_NUMERIC_RND_MASK) == GNC_HOW_RND_NEVER)
-        {
-            return gnc_numeric_error (GNC_ERROR_OVERFLOW);
-        }
-        while (nume.isbig || deno.isbig)
-        {
-            nume = shift128 (nume);
-            deno = shift128 (deno);
-        }
-        quotient.num = sgn * nume.lo;
-        quotient.denom = deno.lo;
-        if (0 == quotient.denom)
-        {
-            return gnc_numeric_error (GNC_ERROR_OVERFLOW);
-        }
-    }
-
-    if (quotient.denom < 0)
+   /* q = (a_num * b_den)/(b_num * a_den). If a_den == b_den they cancel out
+     * and it's just a_num/b_num.
+     */
+    if (an.m_den == bn.m_den)
     {
-        quotient.num   = -quotient.num;
-        quotient.denom = -quotient.denom;
+        GncNumeric q(an.m_num, bn.m_num);
+        q.round(new_denom);
+        return static_cast<gnc_numeric>(q);
     }
-
-dive_done:
-    if ((denom == GNC_DENOM_AUTO) &&
-            ((how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_LCD))
+    /* Protect against possibly preventable overflow: */
+    if (an.m_num.isBig() || an.m_den.isBig() ||
+        bn.m_num.isBig() || bn.m_den.isBig())
     {
-        denom = gnc_numeric_lcd(a, b);
-        how   = how & GNC_NUMERIC_RND_MASK;
+        QofInt128 gcd = bn.m_den.gcd(an.m_den);
+        bn.m_den /= gcd;
+        an.m_den /= gcd;
     }
 
-    return gnc_numeric_convert(quotient, denom, how);
+    GncNumeric q(an.m_num * bn.m_den, bn.m_num * an.m_den);
+    q.round (new_denom);
+    return static_cast<gnc_numeric>(q);
 }
 
 /* *******************************************************************
@@ -769,264 +641,18 @@ gnc_numeric_abs(gnc_numeric a)
     return gnc_numeric_create(ABS(a.num), a.denom);
 }
 
+
 /* *******************************************************************
  *  gnc_numeric_convert
  ********************************************************************/
 
 gnc_numeric
-gnc_numeric_convert(gnc_numeric in, gint64 denom, gint how)
+gnc_numeric_convert(gnc_numeric in, int64_t denom, int how)
 {
-    gnc_numeric out;
-    gnc_numeric temp;
-    gint64      temp_bc;
-    gint64      temp_a;
-    gint64      remainder;
-    gint64      sign;
-    gint        denom_neg = 0;
-    double      ratio, logratio;
-    double      sigfigs;
-    qofint128 nume, newm;
-
-    temp.num   = 0;
-    temp.denom = 0;
-
-    if (gnc_numeric_check(in))
-    {
-        return gnc_numeric_error(GNC_ERROR_ARG);
-    }
-
-    if (denom == GNC_DENOM_AUTO)
-    {
-        switch (how & GNC_NUMERIC_DENOM_MASK)
-        {
-        default:
-        case GNC_HOW_DENOM_LCD:   /* LCD is meaningless with AUTO in here */
-        case GNC_HOW_DENOM_EXACT:
-            return in;
-            break;
-
-        case GNC_HOW_DENOM_REDUCE:
-            /* reduce the input to a relatively-prime fraction */
-            return gnc_numeric_reduce(in);
-            break;
-
-        case GNC_HOW_DENOM_FIXED:
-            if (in.denom != denom)
-            {
-                return gnc_numeric_error(GNC_ERROR_DENOM_DIFF);
-            }
-            else
-            {
-                return in;
-            }
-            break;
-
-        case GNC_HOW_DENOM_SIGFIG:
-            ratio    = fabs(gnc_numeric_to_double(in));
-            if (ratio < 10e-20)
-            {
-                logratio = 0;
-            }
-            else
-            {
-                logratio = log10(ratio);
-                logratio = ((logratio > 0.0) ?
-                            (floor(logratio) + 1.0) : (ceil(logratio)));
-            }
-            sigfigs  = GNC_HOW_GET_SIGFIGS(how);
-
-            if ((denom = powten (sigfigs - logratio)) == POWTEN_OVERFLOW)
-                return gnc_numeric_error(GNC_ERROR_OVERFLOW);
-
-            how = how & ~GNC_HOW_DENOM_SIGFIG & ~GNC_NUMERIC_SIGFIGS_MASK;
-            break;
-
-        }
-    }
-
-    /* Make sure we need to do the work */
-    if (in.denom == denom)
-    {
-        return in;
-    }
-    if (in.num == 0)
-    {
-        out.num = 0;
-        out.denom = denom;
-        return out;
-    }
-
-    /* If the denominator of the input value is negative, get rid of that. */
-    if (in.denom < 0)
-    {
-        in.num = in.num * (- in.denom);  /* BUG: overflow not handled.  */
-        in.denom = 1;
-    }
-
-    sign = (in.num < 0) ? -1 : 1;
-
-    /* If the denominator is less than zero, we are to interpret it as
-     * the reciprocal of its magnitude. */
-    if (denom < 0)
-    {
-
-        /* XXX FIXME: use 128-bit math here ... */
-        denom     = - denom;
-        denom_neg = 1;
-        temp_a    = (in.num < 0) ? -in.num : in.num;
-        temp_bc   = in.denom * denom;  /* BUG: overflow not handled.  */
-        remainder = temp_a % temp_bc;
-        out.num   = temp_a / temp_bc;
-        out.denom = - denom;
-    }
-    else
-    {
-        /* Do all the modulo and int division on positive values to make
-         * things a little clearer. Reduce the fraction denom/in.denom to
-         * help with range errors */
-        temp.num   = denom;
-        temp.denom = in.denom;
-        temp       = gnc_numeric_reduce(temp);
-
-        /* Symbolically, do the following:
-         * out.num   = in.num * temp.num;
-         * remainder = out.num % temp.denom;
-         * out.num   = out.num / temp.denom;
-         * out.denom = denom;
-         */
-        nume = mult128 (in.num, temp.num);
-        newm = div128 (nume, temp.denom);
-        remainder = rem128 (nume, temp.denom);
-
-        if (newm.isbig)
-        {
-            return gnc_numeric_error(GNC_ERROR_OVERFLOW);
-        }
-
-        out.num = newm.lo;
-        out.denom = denom;
-    }
-
-    if (remainder)
-    {
-        switch (how & GNC_NUMERIC_RND_MASK)
-        {
-        case GNC_HOW_RND_FLOOR:
-            if (sign < 0)
-            {
-                out.num = out.num + 1;
-            }
-            break;
-
-        case GNC_HOW_RND_CEIL:
-            if (sign > 0)
-            {
-                out.num = out.num + 1;
-            }
-            break;
-
-        case GNC_HOW_RND_TRUNC:
-            break;
-
-        case GNC_HOW_RND_PROMOTE:
-            out.num = out.num + 1;
-            break;
-
-        case GNC_HOW_RND_ROUND_HALF_DOWN:
-            if (denom_neg)
-            {
-                if ((2 * remainder) > in.denom * denom)
-                {
-                    out.num = out.num + 1;
-                }
-            }
-            else if ((2 * remainder) > temp.denom)
-            {
-                out.num = out.num + 1;
-            }
-            /* check that 2*remainder didn't over-flow */
-            else if (((2 * remainder) < remainder) &&
-                     (remainder > (temp.denom / 2)))
-            {
-                out.num = out.num + 1;
-            }
-            break;
-
-        case GNC_HOW_RND_ROUND_HALF_UP:
-            if (denom_neg)
-            {
-                if ((2 * remainder) >= in.denom * denom)
-                {
-                    out.num = out.num + 1;
-                }
-            }
-            else if ((2 * remainder ) >= temp.denom)
-            {
-                out.num = out.num + 1;
-            }
-            /* check that 2*remainder didn't over-flow */
-            else if (((2 * remainder) < remainder) &&
-                     (remainder >= (temp.denom / 2)))
-            {
-                out.num = out.num + 1;
-            }
-            break;
-
-        case GNC_HOW_RND_ROUND:
-            if (denom_neg)
-            {
-                if ((2 * remainder) > in.denom * denom)
-                {
-                    out.num = out.num + 1;
-                }
-                else if ((2 * remainder) == in.denom * denom)
-                {
-                    if (out.num % 2)
-                    {
-                        out.num = out.num + 1;
-                    }
-                }
-            }
-            else
-            {
-                if ((2 * remainder ) > temp.denom)
-                {
-                    out.num = out.num + 1;
-                }
-                /* check that 2*remainder didn't over-flow */
-                else if (((2 * remainder) < remainder) &&
-                         (remainder > (temp.denom / 2)))
-                {
-                    out.num = out.num + 1;
-                }
-                else if ((2 * remainder) == temp.denom)
-                {
-                    if (out.num % 2)
-                    {
-                        out.num = out.num + 1;
-                    }
-                }
-                /* check that 2*remainder didn't over-flow */
-                else if (((2 * remainder) < remainder) &&
-                         (remainder ==  (temp.denom / 2)))
-                {
-                    if (out.num % 2)
-                    {
-                        out.num = out.num + 1;
-                    }
-                }
-            }
-            break;
-
-        case GNC_HOW_RND_NEVER:
-            return gnc_numeric_error(GNC_ERROR_REMAINDER);
-            break;
-        }
-    }
-
-    out.num = (sign > 0) ? out.num : (-out.num);
-
-    return out;
+    GncNumeric a (in), b (gnc_numeric_zero());
+    GncDenom d (a, b, denom, how);
+    a.round (d);
+    return static_cast<gnc_numeric>(a);
 }
 
 
@@ -1039,30 +665,17 @@ gnc_numeric_convert(gnc_numeric in, gint64 denom, gint how)
 gnc_numeric
 gnc_numeric_reduce(gnc_numeric in)
 {
-    gint64   t;
-    gint64   num = (in.num < 0) ? (- in.num) : in.num ;
-    gint64   denom = in.denom;
-    gnc_numeric out;
-
     if (gnc_numeric_check(in))
     {
         return gnc_numeric_error(GNC_ERROR_ARG);
     }
 
-    /* The strategy is to use Euclid's algorithm */
-    while (denom > 0)
-    {
-        t = num % denom;
-        num = denom;
-        denom = t;
-    }
-    /* num now holds the GCD (Greatest Common Divisor) */
-
-    /* All calculations are done on positive num, since it's not
-     * well defined what % does for negative values */
-    out.num   = in.num / num;
-    out.denom = in.denom / num;
-    return out;
+    if (in.denom < 0) /* Negative denoms multiply num, can't be reduced. */
+        return in;
+    GncNumeric a (in), b (gnc_numeric_zero());
+    GncDenom d (a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE | GNC_HOW_RND_ROUND);
+    a.round (d);
+    return static_cast<gnc_numeric>(a);
 }
 
 
diff --git a/src/libqof/qof/gnc-numeric.h b/src/libqof/qof/gnc-numeric.h
index e8fc666..f0ab18e 100644
--- a/src/libqof/qof/gnc-numeric.h
+++ b/src/libqof/qof/gnc-numeric.h
@@ -516,14 +516,6 @@ gboolean gnc_numeric_to_decimal(gnc_numeric * a,
 GType gnc_numeric_get_type( void );
 #define GNC_TYPE_NUMERIC (gnc_numeric_get_type ())
 
-/** @} */
-/** Int 64 exponentiation. Faster and more robust than casting the result of pow().
- * @param op The number to raise to exp.
- * @param exp The exponent
- * @return A gint64
- */
-gint64 pwr64 (gint64 op, int exp);
-/** @} */
 #ifdef __cplusplus
 }
 #endif

commit ab94094523ecf8df6ed2312b298adbfb5aec1b08
Author: John Ralls <jralls at ceridwen.us>
Date:   Sat Nov 29 13:24:03 2014 -0800

    Lose the value returns for various reasons of inequality.

diff --git a/src/libqof/qof/qofint128.cpp b/src/libqof/qof/qofint128.cpp
index 0fd5f7b..97e7fd8 100644
--- a/src/libqof/qof/qofint128.cpp
+++ b/src/libqof/qof/qofint128.cpp
@@ -104,23 +104,23 @@ int
 QofInt128::cmp (const QofInt128& b) const noexcept
 {
     if (m_flags & (overflow | NaN))
-        return -9;
+        return -1;
     if (b.isOverflow () || b.isNan ())
-        return 9;
+        return 1;
     if (m_flags & neg)
     {
 	if (!b.isNeg()) return -1;
-	if (m_hi > b.m_hi) return -3;
-	if (m_hi < b.m_hi) return 3;
-	if (m_lo > b.m_lo) return -2;
-	if (m_lo < b.m_lo) return 2;
+	if (m_hi > b.m_hi) return -1;
+	if (m_hi < b.m_hi) return 1;
+	if (m_lo > b.m_lo) return -1;
+	if (m_lo < b.m_lo) return 1;
 	return 0;
     }
     if (b.isNeg()) return 1;
-    if (m_hi < b.m_hi) return -5;
-    if (m_hi > b.m_hi) return 5;
-    if (m_lo < b.m_lo) return -4;
-    if (m_lo > b.m_lo) return 4;
+    if (m_hi < b.m_hi) return -1;
+    if (m_hi > b.m_hi) return 1;
+    if (m_lo < b.m_lo) return -1;
+    if (m_lo > b.m_lo) return 1;
     return 0;
 }
 
diff --git a/src/libqof/qof/test/gtest-qofint128.cpp b/src/libqof/qof/test/gtest-qofint128.cpp
index b5572e7..46ec5a5 100644
--- a/src/libqof/qof/test/gtest-qofint128.cpp
+++ b/src/libqof/qof/test/gtest-qofint128.cpp
@@ -218,37 +218,37 @@ TEST(qofint128_functions, test_compare)
     QofInt128 overflowed (INT64_C(0), INT64_C(0), QofInt128::overflow);
     QofInt128 not_a_number (INT64_C(0), INT64_C(0), QofInt128::NaN);
 
-    EXPECT_EQ (-9, overflowed.cmp (big));
-    EXPECT_EQ (-9, not_a_number.cmp (big));
-    EXPECT_EQ (9, big.cmp (overflowed));
-    EXPECT_EQ (9, big.cmp (not_a_number));
+    EXPECT_EQ (-1, overflowed.cmp (big));
+    EXPECT_EQ (-1, not_a_number.cmp (big));
+    EXPECT_EQ (1, big.cmp (overflowed));
+    EXPECT_EQ (1, big.cmp (not_a_number));
 
     EXPECT_EQ (-1, neg_big.cmp(big));
     EXPECT_EQ (-1, neg_big.cmp(small));
     EXPECT_EQ (-1, neg_small.cmp(big));
-    EXPECT_EQ (-2, neg_big.cmp(neg_small));
-    EXPECT_EQ (2, neg_small.cmp(neg_big));
+    EXPECT_EQ (-1, neg_big.cmp(neg_small));
+    EXPECT_EQ (1, neg_small.cmp(neg_big));
 
-    EXPECT_EQ (-4, small.cmp(big));
-    EXPECT_EQ (4, big.cmp(small));
+    EXPECT_EQ (-1, small.cmp(big));
+    EXPECT_EQ (1, big.cmp(small));
     EXPECT_EQ (1, small.cmp(neg_big));
     EXPECT_EQ (1, big.cmp(neg_small));
-    EXPECT_EQ (-5, big.cmp(a_little_smaller));
+    EXPECT_EQ (-1, big.cmp(a_little_smaller));
     EXPECT_EQ (1, big.cmp(neg_a_little_smaller));
 
-    EXPECT_EQ (-4, really_big.cmp(slightly_bigger));
-    EXPECT_EQ (5, really_big.cmp(not_as_big));
-    EXPECT_EQ (-5, big.cmp(really_big));
+    EXPECT_EQ (-1, really_big.cmp(slightly_bigger));
+    EXPECT_EQ (1, really_big.cmp(not_as_big));
+    EXPECT_EQ (-1, big.cmp(really_big));
 
     EXPECT_EQ (-1, neg_really_big.cmp(big));
     EXPECT_EQ (-1, neg_really_big.cmp(not_as_big));
     EXPECT_EQ (-1, neg_really_big.cmp(slightly_bigger));
-    EXPECT_EQ (-3, neg_really_big.cmp(neg_not_as_big));
-    EXPECT_EQ (-3, neg_really_big.cmp(neg_a_little_smaller));
-    EXPECT_EQ (2, neg_really_big.cmp(neg_slightly_bigger));
-    EXPECT_EQ (3, neg_not_as_big.cmp(neg_really_big));
-    EXPECT_EQ (-2, neg_not_as_big.cmp(neg_a_little_smaller));
-    EXPECT_EQ (-3, neg_really_big.cmp(neg_a_little_smaller));
+    EXPECT_EQ (-1, neg_really_big.cmp(neg_not_as_big));
+    EXPECT_EQ (-1, neg_really_big.cmp(neg_a_little_smaller));
+    EXPECT_EQ (1, neg_really_big.cmp(neg_slightly_bigger));
+    EXPECT_EQ (1, neg_not_as_big.cmp(neg_really_big));
+    EXPECT_EQ (-1, neg_not_as_big.cmp(neg_a_little_smaller));
+    EXPECT_EQ (-1, neg_really_big.cmp(neg_a_little_smaller));
 
     EXPECT_EQ (0, neg_really_big.cmp(QofInt128(barg, sarg, QofInt128::neg)));
     EXPECT_EQ (0, really_big.cmp(QofInt128(barg, sarg)));
@@ -303,8 +303,12 @@ TEST(qofint128_functions, add_and_subtract)
     QofInt128 big (sarg, barg);
     QofInt128 bigger (static_cast<uint64_t>(barg), uarg);
     QofInt128 biggest (uarg, static_cast<uint64_t>(barg));
+    QofInt128 nsmall (UINT64_C(0), uarg, QofInt128::neg);
 
     EXPECT_EQ (QofInt128(INT64_C(2), INT64_C(499)), small += smaller);
+    EXPECT_EQ (QofInt128(INT64_C(2), INT64_C(499), QofInt128::neg),
+               nsmall -= smaller);
+
     EXPECT_EQ (QofInt128(uarg), small -= smaller);
     EXPECT_EQ (QofInt128(static_cast<uint64_t>(barg + sarg/2), UINT64_MAX),
                bigger += big);
@@ -352,6 +356,8 @@ TEST(qofint128_functions, divide)
     QofInt128 small (uarg);
     QofInt128 big (sarg, barg);
     QofInt128 bigger (static_cast<uint64_t>(barg), uarg);
+    QofInt128 nsmall = -small;
+    QofInt128 nbig = -bigger;
 
     EXPECT_EQ (QofInt128(INT64_C(0)), zero /= smallest);
     EXPECT_EQ (QofInt128(INT64_C(0)), zero %= smallest);
@@ -364,6 +370,18 @@ TEST(qofint128_functions, divide)
     EXPECT_EQ (two, q);
     EXPECT_EQ (QofInt128(INT64_C(3810195028972355394)), r);
 
+    small.div (-smaller, q, r);
+    EXPECT_EQ (-two, q);
+    EXPECT_EQ (QofInt128(INT64_C(3810195028972355394)), r);
+
+    nsmall.div (smaller, q, r);
+    EXPECT_EQ (-two, q);
+    EXPECT_EQ (QofInt128(INT64_C(3810195028972355394)), r);
+
+    nsmall.div (-smaller, q, r);
+    EXPECT_EQ (two, q);
+    EXPECT_EQ (QofInt128(INT64_C(3810195028972355394)), r);
+
     bigger.div (bigger, q, r);
     EXPECT_EQ (one, q);
     EXPECT_EQ (zero, r);
@@ -381,6 +399,21 @@ TEST(qofint128_functions, divide)
     EXPECT_EQ (QofInt128(UINT64_C(534327326303355007),
                          UINT64_C(3810195028972355394)), r);
 
+    bigger.div (-big, q, r);
+    EXPECT_EQ (-two, q);
+    EXPECT_EQ (QofInt128(UINT64_C(534327326303355007),
+                         UINT64_C(3810195028972355394)), r);
+
+    nbig.div (-big, q, r);
+    EXPECT_EQ (two, q);
+    EXPECT_EQ (QofInt128(UINT64_C(534327326303355007),
+                         UINT64_C(3810195028972355394)), r);
+
+    nbig.div (-big, q, r);
+    EXPECT_EQ (two, q);
+    EXPECT_EQ (QofInt128(UINT64_C(534327326303355007),
+                         UINT64_C(3810195028972355394)), r);
+
     big.div (bigger, q, r);
     EXPECT_EQ (zero, q);
     EXPECT_EQ (big, r);

commit a99335104fe6951ffa5647da65ee10862a813202
Author: John Ralls <jralls at ceridwen.us>
Date:   Sat Nov 29 13:23:18 2014 -0800

    Assert that the quotient and remainder references aren't this.
    
    Otherwise this gets zeroed and produces a wrong result.

diff --git a/src/libqof/qof/qofint128.cpp b/src/libqof/qof/qofint128.cpp
index 9388b95..0fd5f7b 100644
--- a/src/libqof/qof/qofint128.cpp
+++ b/src/libqof/qof/qofint128.cpp
@@ -625,6 +625,10 @@ QofInt128::div (const QofInt128& b, QofInt128& q, QofInt128& r) noexcept
         r.m_flags |= NaN;
         return;
     }
+    assert (&q != this);
+    assert (&r != this);
+    assert (&q != &b);
+    assert (&r != &b);
 
     q.zero(), r.zero();
     if (b.isZero())

commit f4c69dbc48326046f900e01779caf97748af7afb
Author: John Ralls <jralls at ceridwen.us>
Date:   Sat Nov 29 13:22:00 2014 -0800

    Ensure that the sign is correctly preserved and transferred.

diff --git a/src/libqof/qof/qofint128.cpp b/src/libqof/qof/qofint128.cpp
index e95bf4f..9388b95 100644
--- a/src/libqof/qof/qofint128.cpp
+++ b/src/libqof/qof/qofint128.cpp
@@ -170,7 +170,7 @@ QofInt128
 QofInt128::lcm(const QofInt128& b) const noexcept
 {
     auto common = gcd(b);
-    return *this / common * b;
+    return *this / common * b.abs(); //Preserve our sign, discard the other's.
 }
 
 /* Knuth section 4.6.3 */
@@ -351,7 +351,7 @@ QofInt128::operator-= (const QofInt128& b) noexcept
 
     if ((!isNeg() && b.isNeg()) || (isNeg() && !b.isNeg()))
 	return this->operator+= (-b);
-    bool operand_bigger {cmp (b) < 0};
+    bool operand_bigger {abs().cmp (b.abs()) < 0};
     if (operand_bigger)
     {
         m_flags ^= neg; // ^= flips the bit
@@ -494,6 +494,7 @@ div_multi_leg (uint64_t* u, size_t m, uint64_t* v, size_t n, QofInt128& q, QofIn
     uint64_t qv[sublegs] {};
     uint64_t d {(UINT64_C(1) << sublegbits)/(v[n - 1] + UINT64_C(1))};
     uint64_t carry {UINT64_C(0)};
+    bool negative {q.isNeg()};
     for (auto i = 0; i < m; ++i)
     {
         u[i] = u[i] * d + carry;
@@ -580,6 +581,7 @@ div_multi_leg (uint64_t* u, size_t m, uint64_t* v, size_t n, QofInt128& q, QofIn
     q = QofInt128 ((qv[3] << sublegbits) + qv[2], (qv[1] << sublegbits) + qv[0]);
     r = QofInt128 ((u[3] << sublegbits) + u[2], (u[1] << sublegbits) + u[0]);
     r /= d;
+    if (negative) q = -q;
 }
 
 void
@@ -587,6 +589,7 @@ div_single_leg (uint64_t* u, size_t m, uint64_t v, QofInt128& q, QofInt128& r) n
 {
     uint64_t qv[sublegs] {};
     uint64_t carry {};
+    bool negative {q.isNeg()};
     for (int i = m - 1; i >= 0; --i)
     {
         qv[i] = u[i] / v;
@@ -601,6 +604,7 @@ div_single_leg (uint64_t* u, size_t m, uint64_t v, QofInt128& q, QofInt128& r) n
 
     q = QofInt128 ((qv[3] << sublegbits) + qv[2], (qv[1] << sublegbits) + qv[0]);
     r = QofInt128 ((u[3] << sublegbits) + u[2], (u[1] << sublegbits) + u[0]);
+    if (negative) q = -q;
 }
 
 }// namespace
@@ -629,6 +633,10 @@ QofInt128::div (const QofInt128& b, QofInt128& q, QofInt128& r) noexcept
         r.m_flags |= NaN;
         return;
     }
+
+    if (isNeg())
+        q.m_flags |= neg;
+
     if (b.isNeg())
         q.m_flags ^= neg;
 

commit 9e37ad27b354b7e4c0228e14d1aaec4feebc2f5f
Author: John Ralls <jralls at ceridwen.us>
Date:   Wed Nov 19 13:31:19 2014 -0800

    Implement QofInt128.pow.

diff --git a/src/libqof/qof/qofint128.cpp b/src/libqof/qof/qofint128.cpp
index e6d0918..e95bf4f 100644
--- a/src/libqof/qof/qofint128.cpp
+++ b/src/libqof/qof/qofint128.cpp
@@ -173,6 +173,25 @@ QofInt128::lcm(const QofInt128& b) const noexcept
     return *this / common * b;
 }
 
+/* Knuth section 4.6.3 */
+QofInt128
+QofInt128::pow(uint b) const noexcept
+{
+    if (isZero() || (m_lo == 1 && m_hi == 0) || isNan() || isOverflow())
+        return *this;
+    if (b == 0)
+        return QofInt128 (1);
+    QofInt128 retval (1), squares = *this;
+    while (b && !retval.isOverflow())
+    {
+        if (b & 1)
+            retval *= squares;
+        squares *= squares;
+        b >>= 1;
+    }
+    return retval;
+}
+
 bool
 QofInt128::isNeg () const noexcept
 {
diff --git a/src/libqof/qof/qofint128.hpp b/src/libqof/qof/qofint128.hpp
index fa8e427..705ab52 100644
--- a/src/libqof/qof/qofint128.hpp
+++ b/src/libqof/qof/qofint128.hpp
@@ -125,9 +125,11 @@ enum // Values for m_flags
 /**
  * Computes the object raised to the parameter's power
  *
- * @return A QofInt128; it will be NaN if the parameter is negative.
+ * @param b The power to raise this to. No point in taking a QofInt128, any
+ * value greater than 128 would overflow on any value other than 1.
+ * @return A QofInt128
  */
-    QofInt128 pow (const QofInt128& b) const noexcept;
+    QofInt128 pow (uint n) const noexcept;
 
 /**
  * Computes a quotient and a remainder, passed as reference parameters.
diff --git a/src/libqof/qof/test/gtest-qofint128.cpp b/src/libqof/qof/test/gtest-qofint128.cpp
index 339b4a4..b5572e7 100644
--- a/src/libqof/qof/test/gtest-qofint128.cpp
+++ b/src/libqof/qof/test/gtest-qofint128.cpp
@@ -411,3 +411,24 @@ TEST(qofint128_functions, GCD)
     EXPECT_EQ (one, bigger.gcd (smallest));
     EXPECT_EQ (big, smaller.lcm (smallest));
 }
+
+TEST(qofint128_functions, pow)
+{
+
+    int64_t sarg {INT64_C(53309)};
+    int64_t barg {INT64_C(4878849681579065407)};
+    QofInt128 little (sarg);
+    QofInt128 big (barg);
+    auto minus = -little;
+
+    EXPECT_EQ (QofInt128(1), little.pow(0));
+    EXPECT_EQ (QofInt128(0), QofInt128(0).pow(123));
+    EXPECT_EQ (big * big, big.pow(2));
+    EXPECT_EQ (QofInt128(UINT64_C(66326033898754),
+                         UINT64_C(10251549987585143605)), little.pow(7));
+    EXPECT_EQ (QofInt128(UINT64_C(66326033898754),
+                         UINT64_C(10251549987585143605), QofInt128::neg),
+               minus.pow(7));
+    auto over = minus.pow(9);
+    EXPECT_TRUE(over.isOverflow());
+}

commit f5c7b1101d743b735a4409a5dbc3a8f9562504ca
Author: John Ralls <jralls at ceridwen.us>
Date:   Wed Nov 19 10:36:00 2014 -0800

    Implement QofInt128::gcd and lcm.

diff --git a/src/libqof/qof/qofint128.cpp b/src/libqof/qof/qofint128.cpp
index a5c0a4d..e6d0918 100644
--- a/src/libqof/qof/qofint128.cpp
+++ b/src/libqof/qof/qofint128.cpp
@@ -68,7 +68,7 @@ QofInt128::QofInt128 (int64_t upper, int64_t lower, unsigned char flags) :
     m_hi >>= 1;
 }
 
-    QofInt128::QofInt128 (uint64_t upper, uint64_t lower, unsigned char flags) :
+QofInt128::QofInt128 (uint64_t upper, uint64_t lower, unsigned char flags) :
     m_flags {flags}, m_hi {upper},
     m_lo {lower} {}
 
@@ -124,6 +124,55 @@ QofInt128::cmp (const QofInt128& b) const noexcept
     return 0;
 }
 
+/* Knuth 4.5.3 Algo B, recommended by GMP as much faster than Algo A (Euclidean
+ * method).
+ */
+QofInt128
+QofInt128::gcd(QofInt128 b) const noexcept
+{
+    if (b.isZero())
+        return *this;
+    if (isZero())
+        return b;
+
+    if (b.isOverflow() || b.isNan())
+        return b;
+    if (isOverflow() || isNan())
+        return *this;
+
+    QofInt128 a (isNeg() ? -(*this) : *this);
+    if (b.isNeg()) b = -b;
+
+    uint k {};
+    const uint64_t one {1};
+    while (!((a & one) || (b & one))) //B1
+    {
+        a >>= 1;
+        b >>= 1;
+        ++k;
+    }
+    QofInt128 t {a & one ? -b : a}; //B2
+    while (a != b)
+    {
+        while (t && (t & one ^ one)) t >>= 1;  //B3 & B4
+        if (t.isNeg())  //B5
+            b = -t;
+        else
+            a = t;
+        t = a - b;  //B6
+    }
+    return a << k;
+}
+
+/* Since u * v = gcd(u, v) * lcm(u, v), we find lcm by u / gcd * v. */
+
+QofInt128
+QofInt128::lcm(const QofInt128& b) const noexcept
+{
+    auto common = gcd(b);
+    return *this / common * b;
+}
+
 bool
 QofInt128::isNeg () const noexcept
 {
diff --git a/src/libqof/qof/qofint128.hpp b/src/libqof/qof/qofint128.hpp
index 6704ce3..fa8e427 100644
--- a/src/libqof/qof/qofint128.hpp
+++ b/src/libqof/qof/qofint128.hpp
@@ -114,7 +114,7 @@ enum // Values for m_flags
  *
  * @return A QofInt128 having the GCD.
  */
-    QofInt128 gcd (const QofInt128& b) const noexcept;
+    QofInt128 gcd (QofInt128 b) const noexcept;
 /**
  * Computes the Least Common Multiple between the object and parameter
  *
diff --git a/src/libqof/qof/test/gtest-qofint128.cpp b/src/libqof/qof/test/gtest-qofint128.cpp
index 61014f3..339b4a4 100644
--- a/src/libqof/qof/test/gtest-qofint128.cpp
+++ b/src/libqof/qof/test/gtest-qofint128.cpp
@@ -388,3 +388,26 @@ TEST(qofint128_functions, divide)
     EXPECT_EQ (big, big %= bigger);
     EXPECT_EQ (two, bigger /= big);
 }
+
+TEST(qofint128_functions, GCD)
+{
+    int64_t barg {INT64_C(4878849681579065407)};
+    int64_t sarg {INT64_C(4344522355275710401)};
+    uint64_t uarg {UINT64_C(13567894392130486208)};
+
+    QofInt128 one (INT64_C(1));
+    QofInt128 smallest (sarg);
+    QofInt128 smaller (barg);
+    QofInt128 small (uarg);
+
+    QofInt128 big = smaller * smallest;
+    QofInt128 bigger = small * smaller;
+
+    EXPECT_EQ (smaller, big.gcd(smaller));
+    EXPECT_EQ (smallest, big.gcd(smallest));
+    EXPECT_EQ (small, bigger.gcd(small));
+    EXPECT_EQ (smaller, bigger.gcd(smaller));
+    EXPECT_EQ (one, big.gcd (small));
+    EXPECT_EQ (one, bigger.gcd (smallest));
+    EXPECT_EQ (big, smaller.lcm (smallest));
+}

commit 765d5583c157b8ba50c06b7a6b33eb4fda4671a7
Author: John Ralls <jralls at ceridwen.us>
Date:   Wed Nov 19 10:35:34 2014 -0800

    Fix mask error in operator<<= and operator>>=
    
    Must specify 1 as a uint64_t to get the right masks.

diff --git a/src/libqof/qof/qofint128.cpp b/src/libqof/qof/qofint128.cpp
index 1268d9e..a5c0a4d 100644
--- a/src/libqof/qof/qofint128.cpp
+++ b/src/libqof/qof/qofint128.cpp
@@ -246,7 +246,7 @@ QofInt128::operator<<= (uint i) noexcept
         m_lo = 0;
         return *this;
     }
-    uint64_t carry {(m_lo & (((1 << i) - 1) << (legbits - i)))};
+    uint64_t carry {(m_lo & (((UINT64_C(1) << i) - 1) << (legbits - i)))};
     m_lo <<= i;
     m_hi <<= i;
     m_hi += carry;
@@ -263,7 +263,7 @@ QofInt128::operator>>= (uint i) noexcept
         m_lo = 0;
         return *this;
     }
-    uint64_t carry {(m_hi & ((1 << i) - 1))};
+    uint64_t carry {(m_hi & ((UINT64_C(1) << i) - 1))};
     m_lo >>= i;
     m_hi >>= i;
     m_lo += (carry << (legbits - i));

commit 7c22669a76fd711469bc720d2c8e644833215465
Author: John Ralls <jralls at ceridwen.us>
Date:   Mon Nov 17 14:44:38 2014 -0800

    Check for incoming overflow and NaN on all class computational operators.

diff --git a/src/libqof/qof/qofint128.cpp b/src/libqof/qof/qofint128.cpp
index 544b1db..1268d9e 100644
--- a/src/libqof/qof/qofint128.cpp
+++ b/src/libqof/qof/qofint128.cpp
@@ -217,6 +217,13 @@ QofInt128::operator-- (int) noexcept
 QofInt128&
 QofInt128::operator+= (const QofInt128& b) noexcept
 {
+    if (b.isOverflow())
+        m_flags |= overflow;
+    if (b.isNan())
+        m_flags |= NaN;
+
+    if (isOverflow() || isNan())
+        return *this;
     if ((isNeg () && !b.isNeg ()) || (!isNeg () && b.isNeg ()))
 	return this->operator-= (-b);
     uint64_t result = m_lo + b.m_lo;
@@ -266,6 +273,14 @@ QofInt128::operator>>= (uint i) noexcept
 QofInt128&
 QofInt128::operator-= (const QofInt128& b) noexcept
 {
+    if (b.isOverflow())
+        m_flags |= overflow;
+    if (b.isNan())
+        m_flags |= NaN;
+
+    if (isOverflow() || isNan())
+        return *this;
+
     if ((!isNeg() && b.isNeg()) || (isNeg() && !b.isNeg()))
 	return this->operator+= (-b);
     bool operand_bigger {cmp (b) < 0};
@@ -309,6 +324,14 @@ QofInt128::operator*= (const QofInt128& b) noexcept
         m_hi = m_lo = 0;
         return *this;
     }
+    if (b.isOverflow())
+        m_flags |= overflow;
+    if (b.isNan())
+        m_flags |= NaN;
+
+    if (isOverflow() || isNan())
+        return *this;
+
     /* Test for overflow before spending time on the calculation */
     if (m_hi && b.m_hi)
     {
@@ -517,10 +540,25 @@ div_single_leg (uint64_t* u, size_t m, uint64_t v, QofInt128& q, QofInt128& r) n
 void
 QofInt128::div (const QofInt128& b, QofInt128& q, QofInt128& r) noexcept
 {
+    if (isOverflow() || b.isOverflow())
+    {
+        q.m_flags |= overflow;
+        r.m_flags |= overflow;
+        return;
+    }
+
+    if (isNan() || b.isNan())
+    {
+        q.m_flags |= NaN;
+        r.m_flags |= NaN;
+        return;
+    }
+
     q.zero(), r.zero();
     if (b.isZero())
     {
         q.m_flags |= NaN;
+        r.m_flags |= NaN;
         return;
     }
     if (b.isNeg())

commit 296ce314a3863becc612f90f3253c9f5501def47
Author: John Ralls <jralls at ceridwen.us>
Date:   Mon Nov 17 14:43:23 2014 -0800

    Extract a class function bits() to return a size value.
    
    Helps to pre-determine overflow. Also correct the original implementation
    in operator *=, which got the wrong answer.

diff --git a/src/libqof/qof/qofint128.cpp b/src/libqof/qof/qofint128.cpp
index 08069fe..544b1db 100644
--- a/src/libqof/qof/qofint128.cpp
+++ b/src/libqof/qof/qofint128.cpp
@@ -163,6 +163,16 @@ QofInt128::abs() const noexcept
     return *this;
 }
 
+uint
+QofInt128::bits() const noexcept
+{
+    uint bits {static_cast<uint>(m_hi == 0 ? 0 : 64)};
+    uint64_t temp {(m_hi == 0 ? m_lo : m_hi)};
+    for (;temp > 0; temp >>= 1)
+        ++bits;
+    return bits;
+}
+
 
 QofInt128
 QofInt128::operator-() const noexcept
@@ -305,23 +315,8 @@ QofInt128::operator*= (const QofInt128& b) noexcept
         m_flags |= overflow;
         return *this;
     }
-    uint abits {}, bbits {};
-    uint64_t temp {m_lo};
-    do
-        ++abits;
-    while (temp >>= 1);
-    temp = m_hi;
-    do
-        ++abits;
-    while (temp >>= 1);
-    temp = b.m_lo;
-    do
-        ++bbits;
-    while (temp >>= 1);
-    temp = b.m_hi;
-    do
-        ++bbits;
-    while (temp >>= 1);
+
+    uint abits {bits()}, bbits {b.bits()};
     if (abits + bbits > maxbits)
     {
         m_flags |= overflow;
diff --git a/src/libqof/qof/qofint128.hpp b/src/libqof/qof/qofint128.hpp
index c160da2..6704ce3 100644
--- a/src/libqof/qof/qofint128.hpp
+++ b/src/libqof/qof/qofint128.hpp
@@ -180,6 +180,11 @@ enum // Values for m_flags
     bool isZero() const noexcept;
 
 /**
+ * @return the number of bits used to represent the value
+ */
+    uint bits() const noexcept;
+
+/**
  * Fills a supplied buffer with a representation of the number in base 10. If
  * the QofInt128 is overflowed or NaN it will contain the words "Overflow" or
  * "NaN" respectively.

commit 1b288df20d2b52792ec1aae8f3c9c2170001fb5f
Author: John Ralls <jralls at ceridwen.us>
Date:   Mon Nov 17 14:40:39 2014 -0800

    Add bitwise operators and binary operators.

diff --git a/src/libqof/qof/qofint128.cpp b/src/libqof/qof/qofint128.cpp
index 10e11e3..08069fe 100644
--- a/src/libqof/qof/qofint128.cpp
+++ b/src/libqof/qof/qofint128.cpp
@@ -577,6 +577,46 @@ QofInt128::operator%= (const QofInt128& b) noexcept
     return *this;
 }
 
+QofInt128&
+QofInt128::operator&= (const QofInt128& b) noexcept
+{
+    if (b.isOverflow())
+        m_flags |= overflow;
+    if (b.isNan())
+        m_flags |= NaN;
+
+    if (isOverflow() || isNan())
+        return *this;
+
+    m_hi &= b.m_hi;
+    m_lo &= b.m_lo;
+    return *this;
+}
+
+QofInt128&
+QofInt128::operator|= (const QofInt128& b) noexcept
+{
+    m_hi ^= b.m_hi;
+    m_lo ^= b.m_lo;
+    return *this;
+}
+
+QofInt128&
+QofInt128::operator^= (const QofInt128& b) noexcept
+{
+    if (b.isOverflow())
+        m_flags |= overflow;
+    if (b.isNan())
+        m_flags |= NaN;
+
+    if (isOverflow() || isNan())
+        return *this;
+
+    m_hi ^= b.m_hi;
+    m_lo ^= b.m_lo;
+    return *this;
+}
+
 static const uint8_t dec_array_size {5};
 /* Convert a uint128 represented as a binary number into 4 10-digit decimal
  * equivalents. Adapted from Douglas W. Jones, "Binary to Decimal Conversion in
@@ -699,3 +739,72 @@ operator>= (const QofInt128& a, const QofInt128& b) noexcept
     return a.cmp(b) >= 0;
 }
 
+QofInt128
+operator+ (QofInt128 a, const QofInt128& b) noexcept
+{
+    a += b;
+    return a;
+}
+
+QofInt128
+operator- (QofInt128 a, const QofInt128& b) noexcept
+{
+    a -= b;
+    return a;
+}
+QofInt128
+operator* (QofInt128 a, const QofInt128& b) noexcept
+{
+    a *= b;
+    return a;
+}
+
+QofInt128
+operator/ (QofInt128 a, const QofInt128& b) noexcept
+{
+    a /= b;
+    return a;
+}
+
+QofInt128
+operator% (QofInt128 a, const QofInt128& b) noexcept
+{
+    a %= b;
+    return a;
+}
+
+QofInt128
+operator& (QofInt128 a, const QofInt128& b) noexcept
+{
+    a &= b;
+    return a;
+}
+
+QofInt128
+operator| (QofInt128 a, const QofInt128& b) noexcept
+{
+    a |= b;
+    return a;
+}
+
+QofInt128
+operator^ (QofInt128 a, const QofInt128& b) noexcept
+{
+    a ^= b;
+    return a;
+}
+
+QofInt128
+operator<< (QofInt128 a, uint b) noexcept
+{
+    a <<= b;
+    return a;
+}
+
+QofInt128
+operator>> (QofInt128 a, uint b) noexcept
+{
+    a >>= b;
+    return a;
+}
+
diff --git a/src/libqof/qof/qofint128.hpp b/src/libqof/qof/qofint128.hpp
index dc6e4eb..c160da2 100644
--- a/src/libqof/qof/qofint128.hpp
+++ b/src/libqof/qof/qofint128.hpp
@@ -205,17 +205,25 @@ enum // Values for m_flags
     QofInt128& operator*= (const QofInt128& b) noexcept;
     QofInt128& operator/= (const QofInt128& b) noexcept;
     QofInt128& operator%= (const QofInt128& b) noexcept;
+    QofInt128& operator&= (const QofInt128& b) noexcept;
+    QofInt128& operator|= (const QofInt128& b) noexcept;
+    QofInt128& operator^= (const QofInt128& b) noexcept;
 
 };
 
 static const QofInt128 k_qofInt128_Max {UINT64_MAX, UINT64_MAX, QofInt128::pos};
 static const QofInt128 k_qofInt128_Min {UINT64_MAX, UINT64_MAX, QofInt128::neg};
 
-QofInt128 operator+ (QofInt128 a, QofInt128 b) noexcept;
-QofInt128 operator- (QofInt128 a, QofInt128 b) noexcept;
-QofInt128 operator* (QofInt128 a, QofInt128 b) noexcept;
-QofInt128 operator/ (QofInt128 a, QofInt128 b) noexcept;
-QofInt128 operator% (QofInt128 a, QofInt128 b) noexcept;
+QofInt128 operator+ (QofInt128 a, const QofInt128& b) noexcept;
+QofInt128 operator- (QofInt128 a, const QofInt128& b) noexcept;
+QofInt128 operator* (QofInt128 a, const QofInt128& b) noexcept;
+QofInt128 operator/ (QofInt128 a, const QofInt128& b) noexcept;
+QofInt128 operator% (QofInt128 a, const QofInt128& b) noexcept;
+QofInt128 operator& (QofInt128 a, const QofInt128& b) noexcept;
+QofInt128 operator| (QofInt128 a, const QofInt128& b) noexcept;
+QofInt128 operator^ (QofInt128 a, const QofInt128& b) noexcept;
+QofInt128 operator<< (QofInt128 a, uint b) noexcept;
+QofInt128 operator>> (QofInt128 a, uint b) noexcept;
 
 bool operator== (const QofInt128& a, const QofInt128& b) noexcept;
 bool operator!= (const QofInt128& a, const QofInt128& b) noexcept;

commit c649aa97363e3c7d739023cd0c9248a2b8142b6b
Author: John Ralls <jralls at ceridwen.us>
Date:   Mon Nov 17 14:38:57 2014 -0800

    Some more constructors, for convenience.

diff --git a/src/libqof/qof/qofint128.hpp b/src/libqof/qof/qofint128.hpp
index 19b5a05..dc6e4eb 100644
--- a/src/libqof/qof/qofint128.hpp
+++ b/src/libqof/qof/qofint128.hpp
@@ -64,6 +64,10 @@ enum // Values for m_flags
 };
 
     QofInt128 ();
+    QofInt128 (int16_t lower) : QofInt128{static_cast<int64_t>(lower)} {};
+    QofInt128 (uint16_t lower) : QofInt128{static_cast<uint64_t>(lower)} {};
+    QofInt128 (int32_t lower) : QofInt128{static_cast<int64_t>(lower)} {};
+    QofInt128 (uint32_t lower) : QofInt128{static_cast<uint64_t>(lower)} {};
     QofInt128 (int64_t lower);
     QofInt128 (uint64_t lower);
 /**
@@ -74,6 +78,18 @@ enum // Values for m_flags
  * upper, so the lower magnitude will be subracted from UINT64_MAX to
  * obtain the lower limb value.
  */
+    QofInt128 (int16_t upper, int16_t lower, unsigned char flags = '\0') :
+        QofInt128{static_cast<int64_t>(upper), static_cast<int64_t>(lower),
+                      flags} {};
+    QofInt128 (uint16_t upper, uint16_t lower, unsigned char flags = '\0') :
+        QofInt128{static_cast<int64_t>(upper), static_cast<int64_t>(lower),
+                      flags} {};
+    QofInt128 (int32_t upper, int32_t lower, unsigned char flags = '\0') :
+        QofInt128{static_cast<int64_t>(upper), static_cast<int64_t>(lower),
+                      flags} {};
+    QofInt128 (uint32_t upper, uint32_t lower, unsigned char flags = '\0') :
+        QofInt128{static_cast<int64_t>(upper), static_cast<int64_t>(lower),
+                      flags} {};
     QofInt128 (int64_t upper, int64_t lower, unsigned char flags = '\0');
     QofInt128 (uint64_t upper, uint64_t lower, unsigned char flags = '\0');
 

commit 810a6bc8aedafda9cac21e7a3fb59dca52f433e2
Author: John Ralls <jralls at ceridwen.us>
Date:   Mon Nov 17 12:13:34 2014 -0800

    Operators /= and %= plus function div() for QofInt128.

diff --git a/src/libqof/qof/qofint128.cpp b/src/libqof/qof/qofint128.cpp
index c322b01..10e11e3 100644
--- a/src/libqof/qof/qofint128.cpp
+++ b/src/libqof/qof/qofint128.cpp
@@ -30,12 +30,20 @@ extern "C"
 #include "qofint128.hpp"
 
 #include <iomanip>
+#include <utility>
+#include <cassert>
 
 /* All algorithms from Donald E. Knuth, "The Art of Computer
  * Programming, Volume 2: Seminumerical Algorithms", 3rd Ed.,
  * Addison-Wesley, 1998.
  */
 
+namespace {
+    static const uint sublegs = QofInt128::numlegs * 2;
+    static const uint sublegbits = QofInt128::legbits / 2;
+    static const uint64_t sublegmask = (UINT64_C(1) << sublegbits) - 1;
+}
+
 QofInt128::QofInt128 () : m_flags {}, m_hi {0}, m_lo {0}{}
 
 QofInt128::QofInt128 (int64_t lower) :
@@ -340,9 +348,6 @@ QofInt128::operator*= (const QofInt128& b) noexcept
  * algorithms.
  */
 
-    static const uint sublegs = numlegs * 2;
-    static const uint sublegbits = legbits / 2;
-    static const uint sublegmask = (UINT64_C(1) << sublegbits) - 1;
     uint64_t av[sublegs] {(m_lo & sublegmask), (m_lo >> sublegbits),
             (m_hi & sublegmask), (m_hi >> sublegbits)};
     uint64_t bv[sublegs] {(b.m_lo & sublegmask), (b.m_lo >> sublegbits),
@@ -390,15 +395,185 @@ QofInt128::operator*= (const QofInt128& b) noexcept
     return *this;
 }
 
+namespace {
+/* Algorithm from Knuth (full citation at operator*=) p272ff.  Again, there
+ * are faster algorithms out there, but they require much larger numbers to
+ * be of benefit.
+ */
+/* We're using arrays here instead of vectors to avoid an alloc. */
+void
+div_multi_leg (uint64_t* u, size_t m, uint64_t* v, size_t n, QofInt128& q, QofInt128& r) noexcept
+{
+/* D1, Normalization */
+    uint64_t qv[sublegs] {};
+    uint64_t d {(UINT64_C(1) << sublegbits)/(v[n - 1] + UINT64_C(1))};
+    uint64_t carry {UINT64_C(0)};
+    for (auto i = 0; i < m; ++i)
+    {
+        u[i] = u[i] * d + carry;
+        if (u[i] > sublegmask)
+        {
+            carry = u[i] >> sublegbits;
+            u[i] &= sublegmask;
+        }
+        else
+            carry = UINT64_C(0);
+        assert (u[i] <= sublegmask);
+    }
+    if (carry)
+    {
+        u[m++] = carry;
+        carry = UINT64_C(0);
+    }
+    for (auto i = 0; i < n; ++i)
+    {
+        v[i] = v[i] * d + carry;
+        if (v[i] > sublegmask)
+        {
+            carry = v[i] >> sublegbits;
+            v[i] &= sublegmask;
+        }
+        else
+            carry = UINT64_C(0);
+        assert (v[i] < sublegmask);
+    }
+    assert (carry == UINT64_C(0));
+    for (int j = m - n; j >= 0; j--) //D3
+    {
+        int64_t qhat, rhat;
+        qhat = ((u[j + n] << sublegbits) + u[j + n - 1]) / v[n - 1];
+        rhat = ((u[j + n] << sublegbits) + u[j + n - 1]) % v[n - 1];
+
+        while (qhat > sublegmask ||
+               (rhat <= sublegmask &&
+                ((qhat * v[n - 2]) > ((rhat << sublegbits) + u[j + n - 2]))))
+        {
+            --qhat;
+            rhat += v[n - 1];
+        }
+        carry = UINT64_C(0);
+        uint64_t borrow {};
+        for (auto k = 0; k < n; ++k) //D4
+        {
+            auto subend = qhat * v[k] + carry;
+            carry = subend >> sublegbits;
+            subend &= sublegmask;
+            if (u[j + k] >= subend)
+            {
+                u[j + k] = u[j + k] - subend;
+                borrow = UINT64_C(0);
+            }
+            else
+            {
+                if (u[j + k + 1] > 0)
+                    --u[j + k + 1];
+                else
+                    ++borrow;
+                u[j + k] = u[j + k] + sublegmask + 1 - subend;
+                u[j + k] &= sublegmask;
+            }
+        }
+        u[j + n] -= carry;
+        qv[j] = qhat;
+        if (borrow) //D5
+        { //D6
+            --qv[j];
+            carry = UINT64_C(0);
+            for (auto k = 0; k < n; ++k)
+            {
+                u[j + k] += v[k] + carry;
+                if (u[j + k] > sublegmask)
+                {
+                    carry = u[j + k] >> sublegbits;
+                    u[j + k] &= sublegmask;
+                }
+            }
+            u[j + n] += carry;
+        }
+    }//D7
+    q = QofInt128 ((qv[3] << sublegbits) + qv[2], (qv[1] << sublegbits) + qv[0]);
+    r = QofInt128 ((u[3] << sublegbits) + u[2], (u[1] << sublegbits) + u[0]);
+    r /= d;
+}
+
+void
+div_single_leg (uint64_t* u, size_t m, uint64_t v, QofInt128& q, QofInt128& r) noexcept
+{
+    uint64_t qv[sublegs] {};
+    uint64_t carry {};
+    for (int i = m - 1; i >= 0; --i)
+    {
+        qv[i] = u[i] / v;
+        if (i > 0)
+        {
+            u[i - 1] += ((u[i] % v) << sublegbits);
+            u[i] = UINT64_C(0);
+        }
+        else
+            u[i] %= v;
+    }
+
+    q = QofInt128 ((qv[3] << sublegbits) + qv[2], (qv[1] << sublegbits) + qv[0]);
+    r = QofInt128 ((u[3] << sublegbits) + u[2], (u[1] << sublegbits) + u[0]);
+}
+
+}// namespace
+
+void
+QofInt128::div (const QofInt128& b, QofInt128& q, QofInt128& r) noexcept
+{
+    q.zero(), r.zero();
+    if (b.isZero())
+    {
+        q.m_flags |= NaN;
+        return;
+    }
+    if (b.isNeg())
+        q.m_flags ^= neg;
+
+    if (abs() < b.abs())
+    {
+        r = *this;
+        return;
+    }
+    if (m_hi == 0 && b.m_hi == 0) //let the hardware do it
+    {
+        q.m_lo = m_lo / b.m_lo;
+        r.m_lo = m_lo % b.m_lo;
+        return;
+    }
+
+    uint64_t u[sublegs + 2] {(m_lo & sublegmask), (m_lo >> sublegbits),
+            (m_hi & sublegmask), (m_hi >> sublegbits), 0, 0};
+    uint64_t v[sublegs] {(b.m_lo & sublegmask), (b.m_lo >> sublegbits),
+            (b.m_hi & sublegmask), (b.m_hi >> sublegbits)};
+    auto m = u[3] ? 4 : u[2] ? 3 : u[1] ? 2 : u[0] ? 1 : 0;
+    auto n = v[3] ? 4 : v[2] ? 3 : v[1] ? 2 : v[0] ? 1 : 0;
+    if (m == 0 || n == 0) //Shouldn't happen
+        return;
+    if (n == 1)
+        return div_single_leg (u, m, v[0], q, r);
+
+    return div_multi_leg (u, m, v, n, q, r);
+}
+
 QofInt128&
 QofInt128::operator/= (const QofInt128& b) noexcept
 {
+    QofInt128 q {}, r {};
+    div(b, q, r);
+    std::swap (*this, q);
     return *this;
 }
 
 QofInt128&
 QofInt128::operator%= (const QofInt128& b) noexcept
 {
+    QofInt128 q {}, r {};
+    div(b, q, r);
+    std::swap (*this, r);
+    if (q.isNan())
+        m_flags |= NaN;
     return *this;
 }
 
diff --git a/src/libqof/qof/qofint128.hpp b/src/libqof/qof/qofint128.hpp
index 235bfbb..19b5a05 100644
--- a/src/libqof/qof/qofint128.hpp
+++ b/src/libqof/qof/qofint128.hpp
@@ -114,6 +114,17 @@ enum // Values for m_flags
     QofInt128 pow (const QofInt128& b) const noexcept;
 
 /**
+ * Computes a quotient and a remainder, passed as reference parameters.
+ *
+ * 'this' is the dividend. The quotient and remainder args must be initialized
+ * to zero.
+ * @param d The divisor
+ * @param q The quotient; will be NaN if divisor = 0
+ * @param r The remainder; will be 0 if divisor = 0
+ */
+    void div (const QofInt128& d, QofInt128& q, QofInt128& r) noexcept;
+
+/**
  * Explicit conversion to int64_t.
  *
  * @return A int64_t
diff --git a/src/libqof/qof/test/gtest-qofint128.cpp b/src/libqof/qof/test/gtest-qofint128.cpp
index bd090ba..61014f3 100644
--- a/src/libqof/qof/test/gtest-qofint128.cpp
+++ b/src/libqof/qof/test/gtest-qofint128.cpp
@@ -337,3 +337,54 @@ TEST(qofint128_functions, multiply)
     EXPECT_FALSE (smallest.isOverflow());
 
 }
+
+TEST(qofint128_functions, divide)
+{
+    int64_t barg {INT64_C(4878849681579065407)};
+    int64_t sarg {INT64_C(4344522355275710400)};
+    uint64_t uarg {UINT64_C(13567894392130486208)};
+
+    QofInt128 zero (INT64_C(0));
+    QofInt128 one (INT64_C(1));
+    QofInt128 two (INT64_C(2));
+    QofInt128 smallest (sarg);
+    QofInt128 smaller (barg);
+    QofInt128 small (uarg);
+    QofInt128 big (sarg, barg);
+    QofInt128 bigger (static_cast<uint64_t>(barg), uarg);
+
+    EXPECT_EQ (QofInt128(INT64_C(0)), zero /= smallest);
+    EXPECT_EQ (QofInt128(INT64_C(0)), zero %= smallest);
+    smallest /= zero;
+    EXPECT_TRUE (smallest.isNan());
+
+    QofInt128 r {}, q {};
+
+    small.div (smaller, q, r);
+    EXPECT_EQ (two, q);
+    EXPECT_EQ (QofInt128(INT64_C(3810195028972355394)), r);
+
+    bigger.div (bigger, q, r);
+    EXPECT_EQ (one, q);
+    EXPECT_EQ (zero, r);
+
+    bigger.div (one, q, r);
+    EXPECT_EQ (bigger, q);
+    EXPECT_EQ (zero, r);
+
+    big.div (smaller, q, r);
+    EXPECT_EQ (QofInt128(INT64_C(8213236443097627766)), q);
+    EXPECT_EQ (QofInt128(INT64_C(3162679692459777845)), r);
+
+    bigger.div (big, q, r);
+    EXPECT_EQ (two, q);
+    EXPECT_EQ (QofInt128(UINT64_C(534327326303355007),
+                         UINT64_C(3810195028972355394)), r);
+
+    big.div (bigger, q, r);
+    EXPECT_EQ (zero, q);
+    EXPECT_EQ (big, r);
+
+    EXPECT_EQ (big, big %= bigger);
+    EXPECT_EQ (two, bigger /= big);
+}

commit 1c83db5896c1f5f6270a63c069f5eee2d94c4ed0
Author: John Ralls <jralls at ceridwen.us>
Date:   Mon Nov 17 12:09:55 2014 -0800

    Add increment, decrement, and shift-eauals operators to QofInt128.
    
    They'll be needed for division.

diff --git a/src/libqof/qof/qofint128.cpp b/src/libqof/qof/qofint128.cpp
index 02e9c26..c322b01 100644
--- a/src/libqof/qof/qofint128.cpp
+++ b/src/libqof/qof/qofint128.cpp
@@ -173,6 +173,30 @@ QofInt128::operator bool() const noexcept
 }
 
 QofInt128&
+QofInt128::operator++ () noexcept
+{
+    return operator+=(UINT64_C(1));
+}
+
+QofInt128&
+QofInt128::operator++ (int) noexcept
+{
+    return operator+=(UINT64_C(1));
+}
+
+QofInt128&
+QofInt128::operator-- () noexcept
+{
+    return operator-=(UINT64_C(1));
+}
+
+QofInt128&
+QofInt128::operator-- (int) noexcept
+{
+    return operator-=(UINT64_C(1));
+}
+
+QofInt128&
 QofInt128::operator+= (const QofInt128& b) noexcept
 {
     if ((isNeg () && !b.isNeg ()) || (!isNeg () && b.isNeg ()))
@@ -187,6 +211,39 @@ QofInt128::operator+= (const QofInt128& b) noexcept
     return *this;
 }
 
+QofInt128&
+QofInt128::operator<<= (uint i) noexcept
+{
+    if (i > maxbits)
+    {
+        m_flags &= 0xfe;
+        m_hi = 0;
+        m_lo = 0;
+        return *this;
+    }
+    uint64_t carry {(m_lo & (((1 << i) - 1) << (legbits - i)))};
+    m_lo <<= i;
+    m_hi <<= i;
+    m_hi += carry;
+    return *this;
+}
+
+QofInt128&
+QofInt128::operator>>= (uint i) noexcept
+{
+    if (i > maxbits)
+    {
+        m_flags &= 0xfe;
+        m_hi = 0;
+        m_lo = 0;
+        return *this;
+    }
+    uint64_t carry {(m_hi & ((1 << i) - 1))};
+    m_lo >>= i;
+    m_hi >>= i;
+    m_lo += (carry << (legbits - i));
+    return *this;
+}
 
 QofInt128&
 QofInt128::operator-= (const QofInt128& b) noexcept
diff --git a/src/libqof/qof/qofint128.hpp b/src/libqof/qof/qofint128.hpp
index 3abff64..235bfbb 100644
--- a/src/libqof/qof/qofint128.hpp
+++ b/src/libqof/qof/qofint128.hpp
@@ -168,7 +168,11 @@ enum // Values for m_flags
     explicit operator bool() const noexcept;
 
     QofInt128& operator++ () noexcept;
-    QofInt128 operator++ (int) noexcept;
+    QofInt128& operator++ (int) noexcept;
+    QofInt128& operator-- () noexcept;
+    QofInt128& operator-- (int) noexcept;
+    QofInt128& operator<<= (uint i) noexcept;
+    QofInt128& operator>>= (uint i) noexcept;
     QofInt128& operator+= (const QofInt128& b) noexcept;
     QofInt128& operator-= (const QofInt128& b) noexcept;
     QofInt128& operator*= (const QofInt128& b) noexcept;

commit c7752d5d3cd4f9ce6bcdba3e1c7d6b08a14d572d
Author: John Ralls <jralls at ceridwen.us>
Date:   Mon Nov 17 12:08:00 2014 -0800

    Add zero and abs functions to QofInt128.

diff --git a/src/libqof/qof/qofint128.cpp b/src/libqof/qof/qofint128.cpp
index 8cc0580..02e9c26 100644
--- a/src/libqof/qof/qofint128.cpp
+++ b/src/libqof/qof/qofint128.cpp
@@ -64,6 +64,14 @@ QofInt128::QofInt128 (int64_t upper, int64_t lower, unsigned char flags) :
     m_flags {flags}, m_hi {upper},
     m_lo {lower} {}
 
+QofInt128&
+QofInt128::zero () noexcept
+{
+    m_flags = 0;
+    m_lo = m_hi = UINT64_C(0);
+    return *this;
+}
+
 QofInt128::operator int64_t() const
 {
     if ((m_flags & neg) && isBig())
@@ -139,6 +147,16 @@ QofInt128::isZero() const noexcept
 }
 
 QofInt128
+QofInt128::abs() const noexcept
+{
+    if (isNeg())
+        return operator-();
+
+    return *this;
+}
+
+
+QofInt128
 QofInt128::operator-() const noexcept
 {
     auto retval = *this;
diff --git a/src/libqof/qof/qofint128.hpp b/src/libqof/qof/qofint128.hpp
index 6b365c5..3abff64 100644
--- a/src/libqof/qof/qofint128.hpp
+++ b/src/libqof/qof/qofint128.hpp
@@ -42,6 +42,7 @@
  * on an overflowed or NaN QofInt128 will yield an overflowed or NaN
  * result, so calling routines need not check until the end of a
  * chained calculation.
+ * QofInt128 uses implicit copy and move constructors and implicit destructor.
  */
 class QofInt128
 {
@@ -75,6 +76,15 @@ enum // Values for m_flags
  */
     QofInt128 (int64_t upper, int64_t lower, unsigned char flags = '\0');
     QofInt128 (uint64_t upper, uint64_t lower, unsigned char flags = '\0');
+
+/**
+ * Clear the object.
+ *
+ * Sets all member variables to zero.
+ * @return A reference to the object for chaining.
+ */
+    QofInt128& zero() noexcept;
+
 /**
  * Compare function.
  *
@@ -90,7 +100,7 @@ enum // Values for m_flags
  */
     QofInt128 gcd (const QofInt128& b) const noexcept;
 /**
- * Computes the Least Common Multiple between the object and paramter
+ * Computes the Least Common Multiple between the object and parameter
  *
  * @return A QofInt128 having the LCM.
  */
@@ -152,6 +162,7 @@ enum // Values for m_flags
  */
     char* asCharBufR(char* buf) const noexcept;
 
+    QofInt128 abs() const noexcept;
 
     QofInt128 operator-() const noexcept;
     explicit operator bool() const noexcept;

commit 1e6855efe560934f5fab1e4980ffff4ec5690777
Author: John Ralls <jralls at ceridwen.us>
Date:   Sun Nov 9 11:55:59 2014 -0800

    Implement operator*= for QofInt128

diff --git a/src/libqof/qof/qofint128.cpp b/src/libqof/qof/qofint128.cpp
index 09084c6..8cc0580 100644
--- a/src/libqof/qof/qofint128.cpp
+++ b/src/libqof/qof/qofint128.cpp
@@ -210,6 +210,108 @@ QofInt128::operator-= (const QofInt128& b) noexcept
 QofInt128&
 QofInt128::operator*= (const QofInt128& b) noexcept
 {
+    /* Test for 0 first */
+    if (isZero() || b.isZero())
+    {
+        m_hi = m_lo = 0;
+        return *this;
+    }
+    /* Test for overflow before spending time on the calculation */
+    if (m_hi && b.m_hi)
+    {
+        m_flags |= overflow;
+        return *this;
+    }
+    uint abits {}, bbits {};
+    uint64_t temp {m_lo};
+    do
+        ++abits;
+    while (temp >>= 1);
+    temp = m_hi;
+    do
+        ++abits;
+    while (temp >>= 1);
+    temp = b.m_lo;
+    do
+        ++bbits;
+    while (temp >>= 1);
+    temp = b.m_hi;
+    do
+        ++bbits;
+    while (temp >>= 1);
+    if (abits + bbits > maxbits)
+    {
+        m_flags |= overflow;
+        return *this;
+    }
+    /* Handle the sign; ^ flips if b is negative */
+    m_flags ^= (b.m_flags & neg);
+    /* The trivial case */
+    if (abits + bbits <= legbits)
+    {
+        m_lo *= b.m_lo;
+        return *this;
+    }
+
+/* This is Knuth's "classical" multi-precision multiplication algorithm
+ * truncated to a QofInt128 result with the loop unrolled for clarity and with
+ * overflow and zero checks beforehand to save time. See Donald Knuth, "The Art
+ * of Computer Programming Volume 2: Seminumerical Algorithms", Addison-Wesley,
+ * 1998, p 268.
+ *
+ * There are potentially faster algorithms (O(n^1.6) instead of O(n^2) for the
+ * full precision), but this is already close to that fast because of truncation
+ * and it's not clear that the truncation is applicable to the faster
+ * algorithms.
+ */
+
+    static const uint sublegs = numlegs * 2;
+    static const uint sublegbits = legbits / 2;
+    static const uint sublegmask = (UINT64_C(1) << sublegbits) - 1;
+    uint64_t av[sublegs] {(m_lo & sublegmask), (m_lo >> sublegbits),
+            (m_hi & sublegmask), (m_hi >> sublegbits)};
+    uint64_t bv[sublegs] {(b.m_lo & sublegmask), (b.m_lo >> sublegbits),
+            (b.m_hi & sublegmask), (b.m_hi >> sublegbits)};
+    uint64_t rv[sublegs] {};
+    int64_t carry {}, scratch {};
+
+    rv[0] = av[0] * bv[0];
+
+    rv[1] = av[1] * bv [0];
+    scratch = rv[1] + av[0] * bv[1];
+    carry = rv[1] > scratch ? 1 : 0;
+    rv[1] = scratch;
+
+    rv[2] = av[2] * bv[0] + carry; //0xffff^2 + 1 < 0xffffffff, can't overflow
+    scratch = rv[2] + av[1] * bv[1];
+    carry = rv[2] > scratch ? 1 : 0;
+    rv[2] = scratch + av[0] * bv[2];
+    carry += scratch > rv[2] ? 1 : 0;
+
+    rv[3] = av[3] * bv[0] + carry;
+    scratch = rv[3] + av[2] * bv[1];
+    carry = rv[3] > scratch ? 1 : 0;
+    rv[3] = scratch + av[1] * bv[2];
+    carry += scratch > rv[3] ? 1 : 0;
+    scratch = rv[3] + av[0] * bv[3];
+    carry += rv[3] > scratch ? 1 : 0;
+    rv[3] = scratch;
+
+    if (carry) //Shouldn't happen because of the checks above
+    {
+        m_flags |= overflow;
+        return *this;
+    }
+
+    m_lo = rv[0] + (rv[1] << sublegbits);
+    carry = rv[1] >> sublegbits;
+    carry += (rv[1] << sublegbits) > m_lo || rv[0] > m_lo ? 1 : 0;
+    m_hi = rv[2] + (rv[3] << sublegbits) + carry;
+    if ((rv[3] << sublegbits) > m_hi || rv[2] > m_hi || (rv[3] >> sublegbits))
+    {
+        m_flags |= overflow;
+        return *this;
+    }
     return *this;
 }
 
diff --git a/src/libqof/qof/qofint128.hpp b/src/libqof/qof/qofint128.hpp
index 03b2ac9..6b365c5 100644
--- a/src/libqof/qof/qofint128.hpp
+++ b/src/libqof/qof/qofint128.hpp
@@ -50,6 +50,10 @@ class QofInt128
     uint64_t m_lo;
 
 public:
+static const uint numlegs = 2;
+static const uint legbits = 64;
+static const uint maxbits = legbits * numlegs;
+
 enum // Values for m_flags
 {
     pos = 0,
diff --git a/src/libqof/qof/test/gtest-qofint128.cpp b/src/libqof/qof/test/gtest-qofint128.cpp
index 18bd59b..bd090ba 100644
--- a/src/libqof/qof/test/gtest-qofint128.cpp
+++ b/src/libqof/qof/test/gtest-qofint128.cpp
@@ -317,3 +317,23 @@ TEST(qofint128_functions, add_and_subtract)
     EXPECT_TRUE (bigger.isOverflow());
  }
 
+TEST(qofint128_functions, multiply)
+{
+    int64_t barg {INT64_C(4878849681579065407)};
+    int64_t sarg {INT64_C(4344522355275710400)};
+    uint64_t uarg {UINT64_C(13567894392130486208)};
+
+    QofInt128 smallest (sarg);
+    QofInt128 smaller (barg);
+    QofInt128 small (uarg);
+    QofInt128 big (sarg, barg);
+    QofInt128 bigger (static_cast<uint64_t>(barg), uarg);
+
+    small *= big;
+    EXPECT_TRUE (small.isOverflow());
+    big *= bigger;
+    EXPECT_TRUE (big.isOverflow());
+    EXPECT_EQ (QofInt128(UINT64_C(1149052180967758316), UINT64_C(6323251814974894144)), smallest *= smaller);
+    EXPECT_FALSE (smallest.isOverflow());
+
+}

commit d4fdd9ef1788073f56cbbfa173374d96bb87e9dc
Author: John Ralls <jralls at ceridwen.us>
Date:   Wed Oct 29 18:32:47 2014 -0700

    Begin QofInt128 class.
    
    Constructs, adds & subtracts, prints, and compares.
    
    Includes unit tests.

diff --git a/src/libqof/qof/qofint128.cpp b/src/libqof/qof/qofint128.cpp
new file mode 100644
index 0000000..09084c6
--- /dev/null
+++ b/src/libqof/qof/qofint128.cpp
@@ -0,0 +1,349 @@
+/********************************************************************
+ * qofmath128.c -- an 128-bit integer library                       *
+ * Copyright (C) 2004 Linas Vepstas <linas at linas.org>               *
+ * Copyright (C) 2014 John Ralls <jralls at ceridwen.us>               *
+ *                                                                  *
+ * This program is free software; you can redistribute it and/or    *
+ * modify it under the terms of the GNU General Public License as   *
+ * published by the Free Software Foundation; either version 2 of   *
+ * the License, or (at your option) any later version.              *
+ *                                                                  *
+ * This program is distributed in the hope that it will be useful,  *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
+ * GNU General Public License for more details.                     *
+ *                                                                  *
+ * You should have received a copy of the GNU General Public License*
+ * along with this program; if not, contact:                        *
+ *                                                                  *
+ * Free Software Foundation           Voice:  +1-617-542-5942       *
+ * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
+ * Boston, MA  02110-1301,  USA       gnu at gnu.org                   *
+ *                                                                  *
+ *******************************************************************/
+extern "C"
+{
+#include "config.h"
+#include <inttypes.h>
+}
+
+#include "qofint128.hpp"
+
+#include <iomanip>
+
+/* All algorithms from Donald E. Knuth, "The Art of Computer
+ * Programming, Volume 2: Seminumerical Algorithms", 3rd Ed.,
+ * Addison-Wesley, 1998.
+ */
+
+QofInt128::QofInt128 () : m_flags {}, m_hi {0}, m_lo {0}{}
+
+QofInt128::QofInt128 (int64_t lower) :
+    m_flags {static_cast<unsigned char>(lower < 0 ? neg : pos)},
+    m_hi {0},
+    m_lo {static_cast<uint64_t>(lower < 0 ? -lower : lower)} {}
+
+QofInt128::QofInt128 (uint64_t lower) :
+    m_flags {}, m_hi {0}, m_lo {lower} {}
+
+QofInt128::QofInt128 (int64_t upper, int64_t lower, unsigned char flags) :
+    m_flags {static_cast<unsigned char>(flags ^ (upper < 0 ? neg :
+    upper == 0 && lower < 0 ? neg : pos))},
+    m_hi {static_cast<uint64_t>(upper < 0 ? -upper : upper)},
+    m_lo {static_cast<uint64_t>(lower < 0 ? -lower : lower)}
+{
+    if ((upper < 0 && lower > 0) || (upper > 0 && lower < 0))
+	m_lo = (m_hi << 63) - m_lo;
+    else
+        m_lo += (m_hi << 63);
+
+    m_hi >>= 1;
+}
+
+    QofInt128::QofInt128 (uint64_t upper, uint64_t lower, unsigned char flags) :
+    m_flags {flags}, m_hi {upper},
+    m_lo {lower} {}
+
+QofInt128::operator int64_t() const
+{
+    if ((m_flags & neg) && isBig())
+        throw std::underflow_error ("Negative value to large to represent as int64_t");
+    if ((m_flags & (overflow | NaN)) || isBig())
+        throw std::overflow_error ("Value to large to represent as int64_t");
+    int64_t retval = static_cast<int64_t>(m_lo);
+    return m_flags & neg ? -retval : retval;
+}
+
+QofInt128::operator uint64_t() const
+{
+    if (m_flags & neg)
+        throw std::underflow_error ("Can't represent negative value as uint64_t");
+    if ((m_flags & (overflow | NaN)) || (m_hi || m_lo > UINT64_MAX))
+        throw std::overflow_error ("Value to large to represent as uint64_t");
+    return m_lo;
+}
+
+
+int
+QofInt128::cmp (const QofInt128& b) const noexcept
+{
+    if (m_flags & (overflow | NaN))
+        return -9;
+    if (b.isOverflow () || b.isNan ())
+        return 9;
+    if (m_flags & neg)
+    {
+	if (!b.isNeg()) return -1;
+	if (m_hi > b.m_hi) return -3;
+	if (m_hi < b.m_hi) return 3;
+	if (m_lo > b.m_lo) return -2;
+	if (m_lo < b.m_lo) return 2;
+	return 0;
+    }
+    if (b.isNeg()) return 1;
+    if (m_hi < b.m_hi) return -5;
+    if (m_hi > b.m_hi) return 5;
+    if (m_lo < b.m_lo) return -4;
+    if (m_lo > b.m_lo) return 4;
+    return 0;
+}
+
+bool
+QofInt128::isNeg () const noexcept
+{
+    return (m_flags & neg);
+}
+
+bool
+QofInt128::isBig () const noexcept
+{
+    return (m_hi || m_lo > INT64_MAX);
+}
+
+bool
+QofInt128::isOverflow () const noexcept
+{
+    return (m_flags & overflow);
+}
+
+bool
+QofInt128::isNan () const noexcept
+{
+    return (m_flags & NaN);
+}
+
+bool
+QofInt128::isZero() const noexcept
+{
+    return ((m_flags & (overflow | NaN)) == 0 &&  m_hi == 0 && m_lo == 0);
+}
+
+QofInt128
+QofInt128::operator-() const noexcept
+{
+    auto retval = *this;
+    if (isNeg())
+	retval.m_flags ^= neg;
+    else
+	retval.m_flags |= neg;
+    return retval;
+}
+
+QofInt128::operator bool() const noexcept
+{
+    return ! isZero ();
+}
+
+QofInt128&
+QofInt128::operator+= (const QofInt128& b) noexcept
+{
+    if ((isNeg () && !b.isNeg ()) || (!isNeg () && b.isNeg ()))
+	return this->operator-= (-b);
+    uint64_t result = m_lo + b.m_lo;
+    uint64_t carry = static_cast<int64_t>(result < m_lo);  //Wrapping
+    m_lo = result;
+    result = m_hi + b.m_hi + carry;
+    if (result < m_hi)
+	m_flags |= overflow;
+    m_hi = result;
+    return *this;
+}
+
+
+QofInt128&
+QofInt128::operator-= (const QofInt128& b) noexcept
+{
+    if ((!isNeg() && b.isNeg()) || (isNeg() && !b.isNeg()))
+	return this->operator+= (-b);
+    bool operand_bigger {cmp (b) < 0};
+    if (operand_bigger)
+    {
+        m_flags ^= neg; // ^= flips the bit
+        uint64_t far_hi {b.m_hi};
+        if (m_lo > b.m_lo)
+        {
+            /* The + 1 on the end is because we really want to use 2^64, or
+             * UINT64_MAX + 1, but that can't be represented in a uint64_t.
+             */
+            m_lo = UINT64_MAX - m_lo + b.m_lo + 1;
+            --far_hi; //borrow
+        }
+        else
+            m_lo = b.m_lo - m_lo;
+
+        m_hi = far_hi - m_hi;
+        return *this;
+    }
+    if (m_lo < b.m_lo)
+    {
+        m_lo = UINT64_MAX - b.m_lo + m_lo + 1; //See UINT64_MAX comment above
+        --m_hi; //borrow
+    }
+    else
+        m_lo -= b.m_lo;
+
+    m_hi -= b.m_hi;
+
+    return *this;
+}
+
+QofInt128&
+QofInt128::operator*= (const QofInt128& b) noexcept
+{
+    return *this;
+}
+
+QofInt128&
+QofInt128::operator/= (const QofInt128& b) noexcept
+{
+    return *this;
+}
+
+QofInt128&
+QofInt128::operator%= (const QofInt128& b) noexcept
+{
+    return *this;
+}
+
+static const uint8_t dec_array_size {5};
+/* Convert a uint128 represented as a binary number into 4 10-digit decimal
+ * equivalents. Adapted from Douglas W. Jones, "Binary to Decimal Conversion in
+ * Limited Precision", http://homepage.cs.uiowa.edu/~jones/bcd/decimal.html,
+ * accessed 28 Oct 2014. */
+static void
+decimal_from_binary (uint64_t d[dec_array_size], uint64_t hi, uint64_t lo)
+{
+    /* Coefficients are the values of 2^96, 2^64, and 2^32 divided into 8-digit
+     * segments:
+     * 2^96 =               79228,16251426,43375935,43950336
+     * 2^64 =                         1844,67440737,09551616
+     * 2^32 =                                    42,94967296
+     */
+    const uint8_t coeff_array_size = dec_array_size - 1;
+    const uint32_t coeff_3 [coeff_array_size] {79228, 16251426, 43375935, 43950336};
+    const uint32_t coeff_2 [coeff_array_size] {0, 1844, 67440737, 9551616};
+    const uint32_t coeff_1 [coeff_array_size] {0, 0, 42, 94967296};
+    const uint32_t bin_mask {0xffffffff};
+    const uint32_t dec_div {UINT32_C(100000000)};
+    const uint8_t last {dec_array_size - 1};
+
+    d[0] = lo & bin_mask;
+    d[1] = (lo >> 32) & bin_mask;
+    d[2] = hi & bin_mask;
+    d[3] = (hi >> 32) & bin_mask, 0;
+
+    d[0] += coeff_3[3] * d[3] + coeff_2[3] * d[2] + coeff_1[3] * d[1];
+    uint64_t q {d[0] / dec_div};
+    d[0] %= dec_div;
+
+    for (int i {1}; i < coeff_array_size; ++i)
+    {
+        int j = coeff_array_size - i - 1;
+        d[i] = q + coeff_3[j] * d[3] + coeff_2[j] * d[2] + coeff_1[j] * d[1];
+        q = d[i] / dec_div;
+        d[i] %= dec_div;
+    }
+    d[last] = q;
+    return;
+}
+
+static const uint8_t char_buf_size {41}; //39 digits plus sign and trailing null
+
+char*
+QofInt128::asCharBufR(char* buf) const noexcept
+{
+    if (isOverflow())
+    {
+        sprintf (buf, "%s", "Overflow");
+        return buf;
+    }
+    if (isNan())
+    {
+        sprintf (buf, "%s", "NaN");
+        return buf;
+    }
+    uint64_t d[dec_array_size] {};
+    decimal_from_binary(d, m_hi, m_lo);
+    char* next = buf;
+    char neg {'-'};
+
+    if (isNeg()) *(next++) = neg;
+    bool trailing {false};
+    for (uint i {dec_array_size}; i; --i)
+        if (d[i - 1] || trailing)
+        {
+            if (trailing)
+                next += sprintf (next, "%8.8" PRIu64, d[i - 1]);
+            else
+                next += sprintf (next, "%" PRIu64, d[i - 1]);
+
+            trailing = true;
+        }
+
+    return buf;
+}
+
+std::ostream&
+operator<< (std::ostream& stream, const QofInt128& a) noexcept
+{
+    char buf[char_buf_size] {};
+    stream << a.asCharBufR (buf);
+    return stream;
+}
+
+bool
+operator== (const QofInt128& a, const QofInt128& b) noexcept
+{
+    return a.cmp(b) == 0;
+}
+
+bool
+operator!= (const QofInt128& a, const QofInt128& b) noexcept
+{
+    return a.cmp(b) != 0;
+}
+
+bool
+operator< (const QofInt128& a, const QofInt128& b) noexcept
+{
+    return a.cmp(b) < 0;
+}
+
+bool
+operator> (const QofInt128& a, const QofInt128& b) noexcept
+{
+    return a.cmp(b) > 0;
+}
+
+bool
+operator<= (const QofInt128& a, const QofInt128& b) noexcept
+{
+    return a.cmp(b) <= 0;
+}
+
+bool
+operator>= (const QofInt128& a, const QofInt128& b) noexcept
+{
+    return a.cmp(b) >= 0;
+}
+
diff --git a/src/libqof/qof/qofint128.hpp b/src/libqof/qof/qofint128.hpp
new file mode 100644
index 0000000..03b2ac9
--- /dev/null
+++ b/src/libqof/qof/qofint128.hpp
@@ -0,0 +1,193 @@
+/********************************************************************
+ * qofmath128.h -- an 128-bit integer library                       *
+ * Copyright (C) 2004 Linas Vepstas <linas at linas.org>               *
+ * Copyright (C) 2014 John Ralls <jralls at ceridwen.us>               *
+ *                                                                  *
+ * This program is free software; you can redistribute it and/or    *
+ * modify it under the terms of the GNU General Public License as   *
+ * published by the Free Software Foundation; either version 2 of   *
+ * the License, or (at your option) any later version.              *
+ *                                                                  *
+ * This program is distributed in the hope that it will be useful,  *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
+ * GNU General Public License for more details.                     *
+ *                                                                  *
+ * You should have received a copy of the GNU General Public License*
+ * along with this program; if not, contact:                        *
+ *                                                                  *
+ * Free Software Foundation           Voice:  +1-617-542-5942       *
+ * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
+ * Boston, MA  02110-1301,  USA       gnu at gnu.org                   *
+ *                                                                  *
+ *******************************************************************/
+
+#ifndef QOFINT128_H
+#define QOFINT128_H
+
+#include <stdint.h>
+
+#include <stdexcept>
+#include <string>
+#include <ostream>
+
+//using std::string;
+
+/**
+ * @brief provides a 128-bit int as a base class for GncNumeric.
+ *
+ * All the usual operators are provided. Only the explicit integer
+ * conversions throw; all other errors are indicated by the overflow
+ * and NaN ("Not a Number") flags. Note that performing any operation
+ * on an overflowed or NaN QofInt128 will yield an overflowed or NaN
+ * result, so calling routines need not check until the end of a
+ * chained calculation.
+ */
+class QofInt128
+{
+    unsigned char m_flags;
+    uint64_t m_hi;
+    uint64_t m_lo;
+
+public:
+enum // Values for m_flags
+{
+    pos = 0,
+    neg = 1,
+    overflow = 2,
+    NaN = 4
+};
+
+    QofInt128 ();
+    QofInt128 (int64_t lower);
+    QofInt128 (uint64_t lower);
+/**
+ * Construct a QofInt128 from two int64_t.
+ *
+ * N.B.: If the two parameters are of differing sign, it's taken to
+ * mean that the lower magnitude is *reducing* the magnitude of the
+ * upper, so the lower magnitude will be subracted from UINT64_MAX to
+ * obtain the lower limb value.
+ */
+    QofInt128 (int64_t upper, int64_t lower, unsigned char flags = '\0');
+    QofInt128 (uint64_t upper, uint64_t lower, unsigned char flags = '\0');
+/**
+ * Compare function.
+ *
+ * @return -1 if the object is less than the parameter, 0 if they're
+ * equal, and 1 if the object is greater.
+ */
+    int cmp (const QofInt128& b) const noexcept;
+
+/**
+ * Computes the Greatest Common Divisor between the object and paramter
+ *
+ * @return A QofInt128 having the GCD.
+ */
+    QofInt128 gcd (const QofInt128& b) const noexcept;
+/**
+ * Computes the Least Common Multiple between the object and paramter
+ *
+ * @return A QofInt128 having the LCM.
+ */
+    QofInt128 lcm (const QofInt128& b) const noexcept;
+
+/**
+ * Computes the object raised to the parameter's power
+ *
+ * @return A QofInt128; it will be NaN if the parameter is negative.
+ */
+    QofInt128 pow (const QofInt128& b) const noexcept;
+
+/**
+ * Explicit conversion to int64_t.
+ *
+ * @return A int64_t
+ * @throws std::overflow_error if the object's value is > INT64_MAX or NaN.
+ * @throws std::underflow_error if the object's value is < INT64_MIN
+ */
+    explicit operator int64_t() const;
+/**
+ * Explicit conversion to uint64_t.
+ *
+ * @return A uint64_t
+ * @throws std::overflow_error if the object's value is > UINT64_MAX or NaN.
+ * @throws std::underflow_error if the object's value is < 0.
+ */
+    explicit operator uint64_t() const;
+
+/**
+ * @return true if the object value is < 0
+ */
+    bool isNeg () const noexcept;
+/**
+ * @return true if the object value is > INT64_MAX or < INT64_MIN
+ */
+    bool isBig () const noexcept;
+/**
+ * @return true if a calculation has produced a result of larger
+ * magnitude than can be contained in the 128 bits available.
+ */
+    bool isOverflow () const noexcept;
+/**
+ * @return true if an illegal calculation has occured.
+ */
+    bool isNan () const noexcept;
+/**
+ * @return true if the object represents 0.
+ */
+    bool isZero() const noexcept;
+
+/**
+ * Fills a supplied buffer with a representation of the number in base 10. If
+ * the QofInt128 is overflowed or NaN it will contain the words "Overflow" or
+ * "NaN" respectively.
+ *
+ * @param buf char[41], 39 digits plus sign and trailing 0.
+ * @return pointer to the buffer for convenience
+ */
+    char* asCharBufR(char* buf) const noexcept;
+
+
+    QofInt128 operator-() const noexcept;
+    explicit operator bool() const noexcept;
+
+    QofInt128& operator++ () noexcept;
+    QofInt128 operator++ (int) noexcept;
+    QofInt128& operator+= (const QofInt128& b) noexcept;
+    QofInt128& operator-= (const QofInt128& b) noexcept;
+    QofInt128& operator*= (const QofInt128& b) noexcept;
+    QofInt128& operator/= (const QofInt128& b) noexcept;
+    QofInt128& operator%= (const QofInt128& b) noexcept;
+
+};
+
+static const QofInt128 k_qofInt128_Max {UINT64_MAX, UINT64_MAX, QofInt128::pos};
+static const QofInt128 k_qofInt128_Min {UINT64_MAX, UINT64_MAX, QofInt128::neg};
+
+QofInt128 operator+ (QofInt128 a, QofInt128 b) noexcept;
+QofInt128 operator- (QofInt128 a, QofInt128 b) noexcept;
+QofInt128 operator* (QofInt128 a, QofInt128 b) noexcept;
+QofInt128 operator/ (QofInt128 a, QofInt128 b) noexcept;
+QofInt128 operator% (QofInt128 a, QofInt128 b) noexcept;
+
+bool operator== (const QofInt128& a, const QofInt128& b) noexcept;
+bool operator!= (const QofInt128& a, const QofInt128& b) noexcept;
+bool operator<= (const QofInt128& a, const QofInt128& b) noexcept;
+bool operator>= (const QofInt128& a, const QofInt128& b) noexcept;
+bool operator< (const QofInt128& a, const QofInt128& b) noexcept;
+bool operator> (const QofInt128& a, const QofInt128& b) noexcept;
+
+std::ostream& operator<< (std::ostream&, const QofInt128&) noexcept;
+
+/** Compute the greatest common denominator of two integers
+ */
+QofInt128 gcd (int64_t a, int64_t b);
+
+/** Compute the least common multiple of two integers
+ */
+QofInt128 lcm (int64_t a, int64_t b);
+
+#endif //QOFINT128_H
+
+/** @} */
diff --git a/src/libqof/qof/test/Makefile.am b/src/libqof/qof/test/Makefile.am
index 2641069..0c0210f 100644
--- a/src/libqof/qof/test/Makefile.am
+++ b/src/libqof/qof/test/Makefile.am
@@ -33,6 +33,23 @@ check_PROGRAMS = \
 
 TESTS = ${check_PROGRAMS}
 
+if WITH_GOOGLE_TEST
+test_qofint128_SOURCES = \
+        $(top_srcdir)/${MODULEPATH}/qofint128.cpp \
+        ${GTEST_ROOT}/src/gtest_main.cc \
+        gtest-qofint128.cpp
+
+test_qofint128_CPPFLAGS = \
+        -I${GTEST_HEADERS} \
+        ${GLIB_CFLAGS}
+
+test_qofint128_LDADD = \
+        ${GLIB_LIBS} \
+        $(top_builddir)/src/test-core/libgtest.a
+
+check_PROGRAMS += test-qofint128
+endif
+
 test_qofdir = ${GNC_LIBEXECDIR}/${MODULEPATH}/test
 
 #The tests might require more libraries, but try to keep them
diff --git a/src/libqof/qof/test/gtest-qofint128.cpp b/src/libqof/qof/test/gtest-qofint128.cpp
new file mode 100644
index 0000000..18bd59b
--- /dev/null
+++ b/src/libqof/qof/test/gtest-qofint128.cpp
@@ -0,0 +1,319 @@
+/********************************************************************
+ * gtest-qofmath128.cpp -- unit tests for the QofInt128 class       *
+ * Copyright (C) 2014 John Ralls <jralls at ceridwen.us>               *
+ *                                                                  *
+ * This program is free software; you can redistribute it and/or    *
+ * modify it under the terms of the GNU General Public License as   *
+ * published by the Free Software Foundation; either version 2 of   *
+ * the License, or (at your option) any later version.              *
+ *                                                                  *
+ * This program is distributed in the hope that it will be useful,  *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
+ * GNU General Public License for more details.                     *
+ *                                                                  *
+ * You should have received a copy of the GNU General Public License*
+ * along with this program; if not, contact:                        *
+ *                                                                  *
+ * Free Software Foundation           Voice:  +1-617-542-5942       *
+ * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
+ * Boston, MA  02110-1301,  USA       gnu at gnu.org                   *
+ *                                                                  *
+ *******************************************************************/
+
+#include <gtest/gtest.h>
+#include "../qofint128.hpp"
+
+TEST(qofint128_constructors, test_default_constructor)
+{
+    QofInt128 value {};
+    EXPECT_EQ (true, value.isZero());
+    EXPECT_EQ (false, value.isNeg());
+    EXPECT_EQ (false, value.isBig());
+    EXPECT_EQ (false, value.isOverflow());
+    EXPECT_EQ (false, value.isNan());
+}
+
+TEST(qofint128_constructors, test_single_arg_constructor)
+{
+    QofInt128 value1 (INT64_C(0));
+    EXPECT_EQ (true, value1.isZero());
+    EXPECT_EQ (false, value1.isNeg());
+    EXPECT_EQ (false, value1.isBig());
+    EXPECT_EQ (false, value1.isOverflow());
+    EXPECT_EQ (false, value1.isNan());
+
+    QofInt128 value2 (INT64_C(567894392130486208));
+    EXPECT_EQ (false, value2.isZero());
+    EXPECT_EQ (false, value2.isNeg());
+    EXPECT_EQ (false, value2.isBig());
+    EXPECT_EQ (false, value2.isOverflow());
+    EXPECT_EQ (false, value2.isNan());
+
+    QofInt128 value3 (INT64_C(-567894392130486208));
+    EXPECT_EQ (false, value3.isZero());
+    EXPECT_EQ (true, value3.isNeg());
+    EXPECT_EQ (false, value3.isBig());
+    EXPECT_EQ (false, value3.isOverflow());
+    EXPECT_EQ (false, value3.isNan());
+
+    QofInt128 value4 (UINT64_C(13567894392130486208));
+    EXPECT_EQ (false, value4.isZero());
+    EXPECT_EQ (false, value4.isNeg());
+    EXPECT_EQ (true, value4.isBig());
+    EXPECT_EQ (false, value4.isOverflow());
+    EXPECT_EQ (false, value4.isNan());
+}
+
+TEST(qofint128_constructors, test_double_arg_constructor)
+{
+    QofInt128 value1 (INT64_C(0), INT64_C(0));
+    EXPECT_EQ (true, value1.isZero());
+    EXPECT_EQ (false, value1.isNeg());
+    EXPECT_EQ (false, value1.isBig());
+    EXPECT_EQ (false, value1.isOverflow());
+    EXPECT_EQ (false, value1.isNan());
+
+    QofInt128 value2 (INT64_C(0), INT64_C(567894392130486208));
+    EXPECT_EQ (false, value2.isZero());
+    EXPECT_EQ (false, value2.isNeg());
+    EXPECT_EQ (false, value2.isBig());
+    EXPECT_EQ (false, value2.isOverflow());
+    EXPECT_EQ (false, value2.isNan());
+
+    QofInt128 value3 (INT64_C(567894392130486208), INT64_C(0));
+    EXPECT_EQ (false, value3.isZero());
+    EXPECT_EQ (false, value3.isNeg());
+    EXPECT_EQ (true, value3.isBig());
+    EXPECT_EQ (false, value3.isOverflow());
+    EXPECT_EQ (false, value3.isNan());
+
+    QofInt128 value4 (INT64_C(567894392130486208), INT64_C(567894392130486208));
+    EXPECT_EQ (false, value4.isZero());
+    EXPECT_EQ (false, value4.isNeg());
+    EXPECT_EQ (true, value4.isBig());
+    EXPECT_EQ (false, value4.isOverflow());
+    EXPECT_EQ (false, value4.isNan());
+
+    QofInt128 value5 (INT64_C(567894392130486208),
+                      INT64_C(-567894392130486208));
+    EXPECT_EQ (false, value5.isZero());
+    EXPECT_EQ (false, value5.isNeg());
+    EXPECT_EQ (true, value5.isBig());
+    EXPECT_EQ (false, value5.isOverflow());
+    EXPECT_EQ (false, value5.isNan());
+
+    QofInt128 value6 (INT64_C(-567894392130486208),
+                      INT64_C(567894392130486208));
+    EXPECT_EQ (false, value6.isZero());
+    EXPECT_EQ (true, value6.isNeg());
+    EXPECT_EQ (true, value6.isBig());
+    EXPECT_EQ (false, value6.isOverflow());
+    EXPECT_EQ (false, value6.isNan());
+
+    QofInt128 value7 (UINT64_C(13567894392130486208),
+                      UINT64_C(13567894392130486208), QofInt128::pos);
+    EXPECT_EQ (false, value7.isZero());
+    EXPECT_EQ (false, value7.isNeg());
+    EXPECT_EQ (true, value7.isBig());
+    EXPECT_EQ (false, value7.isOverflow());
+    EXPECT_EQ (false, value7.isNan());
+
+    QofInt128 value8 (UINT64_C(13567894392130486208),
+                      UINT64_C(13567894392130486208), QofInt128::neg);
+    EXPECT_EQ (false, value8.isZero());
+    EXPECT_EQ (true, value8.isNeg());
+    EXPECT_EQ (true, value8.isBig());
+    EXPECT_EQ (false, value8.isOverflow());
+    EXPECT_EQ (false, value8.isNan());
+
+    QofInt128 value9 (UINT64_C(13567894392130486208),
+                      UINT64_C(13567894392130486208), QofInt128::overflow);
+    EXPECT_EQ (false, value9.isZero());
+    EXPECT_EQ (false, value9.isNeg());
+    EXPECT_EQ (true, value9.isBig());
+    EXPECT_EQ (true, value9.isOverflow());
+    EXPECT_EQ (false, value9.isNan());
+
+   QofInt128 value10 (UINT64_C(13567894392130486208),
+                      UINT64_C(13567894392130486208), QofInt128::NaN);
+    EXPECT_EQ (false, value10.isZero());
+    EXPECT_EQ (false, value10.isNeg());
+    EXPECT_EQ (true, value10.isBig());
+    EXPECT_EQ (false, value10.isOverflow());
+    EXPECT_EQ (true, value10.isNan());
+}
+
+TEST(qofint128_functions, test_int_functions)
+{
+    int64_t arg {INT64_C(567894392130486208)};
+    int64_t narg {INT64_C(-567894392130486208)};
+    uint64_t uarg {UINT64_C(13567894392130486208)};
+    QofInt128 value1 (INT64_C(0), arg);
+    EXPECT_EQ (arg, static_cast<int64_t>(value1));
+    EXPECT_EQ (static_cast<uint64_t>(arg), static_cast<uint64_t>(value1));
+
+    QofInt128 value2 (UINT64_C(0), uarg);
+    EXPECT_THROW (static_cast<int64_t>(value2), std::overflow_error);
+    EXPECT_EQ (uarg, static_cast<uint64_t>(value2));
+
+    QofInt128 value3 (UINT64_C(0), uarg, QofInt128::neg);
+    EXPECT_THROW (static_cast<int64_t>(value3), std::underflow_error);
+    EXPECT_THROW (static_cast<uint64_t>(value3), std::underflow_error);
+
+    QofInt128 value4 (UINT64_C(0), uarg, QofInt128::overflow);
+    EXPECT_THROW (static_cast<int64_t>(value4), std::overflow_error);
+    EXPECT_THROW (static_cast<uint64_t>(value4), std::overflow_error);
+
+    QofInt128 value5 (UINT64_C(0), uarg, QofInt128::NaN);
+    EXPECT_THROW (static_cast<int64_t>(value5), std::overflow_error);
+    EXPECT_THROW (static_cast<uint64_t>(value5), std::overflow_error);
+
+    QofInt128 value6 (INT64_C(1), arg);
+    EXPECT_THROW (static_cast<int64_t>(value6), std::overflow_error);
+    EXPECT_EQ (arg + (UINT64_C(0x1) << 63), static_cast<uint64_t>(value6));
+
+    QofInt128 value7 (INT64_C(-1), arg);
+    EXPECT_EQ (-static_cast<int64_t>((UINT64_C(0x1) << 63) - arg),
+               static_cast<int64_t>(value7));
+    EXPECT_THROW (static_cast<uint64_t>(value7), std::underflow_error);
+
+    QofInt128 value8 (INT64_C(0), narg);
+    EXPECT_EQ (narg, static_cast<int64_t>(value8));
+    EXPECT_THROW (static_cast<uint64_t>(value8), std::underflow_error);
+
+    QofInt128 value9 (INT64_C(1), narg);
+    EXPECT_EQ (static_cast<int64_t>((UINT64_C(0x1) << 63) + narg),
+               static_cast<int64_t>(value9));
+    EXPECT_EQ ((UINT64_C(0x1) << 63) + narg, static_cast<uint64_t>(value9));
+
+    QofInt128 value10 (INT64_C(-2), arg);
+    EXPECT_THROW (static_cast<int64_t>(value10), std::underflow_error);
+    EXPECT_THROW (static_cast<uint64_t>(value10), std::underflow_error);
+
+}
+
+TEST(qofint128_functions, test_compare)
+{
+    int64_t barg {INT64_C(567894392130486208)};
+    int64_t nbarg {INT64_C(-567894392130486208)};
+    int64_t sarg {INT64_C(567894392130486207)};
+    int64_t nsarg {INT64_C(-567894392130486207)};
+
+    QofInt128 big (barg);
+    QofInt128 small (sarg);
+    QofInt128 neg_big (nbarg);
+    QofInt128 neg_small (nsarg);
+
+    QofInt128 really_big (barg, sarg);
+    QofInt128 slightly_bigger (barg, barg);
+    QofInt128 not_as_big (sarg, barg);
+    QofInt128 a_little_smaller (sarg, sarg);
+
+    QofInt128 neg_really_big (barg, sarg, QofInt128::neg);
+    QofInt128 neg_slightly_bigger (barg, barg, QofInt128::neg);
+    QofInt128 neg_not_as_big (sarg, barg, QofInt128::neg);
+    QofInt128 neg_a_little_smaller (sarg, sarg, QofInt128::neg);
+
+    QofInt128 overflowed (INT64_C(0), INT64_C(0), QofInt128::overflow);
+    QofInt128 not_a_number (INT64_C(0), INT64_C(0), QofInt128::NaN);
+
+    EXPECT_EQ (-9, overflowed.cmp (big));
+    EXPECT_EQ (-9, not_a_number.cmp (big));
+    EXPECT_EQ (9, big.cmp (overflowed));
+    EXPECT_EQ (9, big.cmp (not_a_number));
+
+    EXPECT_EQ (-1, neg_big.cmp(big));
+    EXPECT_EQ (-1, neg_big.cmp(small));
+    EXPECT_EQ (-1, neg_small.cmp(big));
+    EXPECT_EQ (-2, neg_big.cmp(neg_small));
+    EXPECT_EQ (2, neg_small.cmp(neg_big));
+
+    EXPECT_EQ (-4, small.cmp(big));
+    EXPECT_EQ (4, big.cmp(small));
+    EXPECT_EQ (1, small.cmp(neg_big));
+    EXPECT_EQ (1, big.cmp(neg_small));
+    EXPECT_EQ (-5, big.cmp(a_little_smaller));
+    EXPECT_EQ (1, big.cmp(neg_a_little_smaller));
+
+    EXPECT_EQ (-4, really_big.cmp(slightly_bigger));
+    EXPECT_EQ (5, really_big.cmp(not_as_big));
+    EXPECT_EQ (-5, big.cmp(really_big));
+
+    EXPECT_EQ (-1, neg_really_big.cmp(big));
+    EXPECT_EQ (-1, neg_really_big.cmp(not_as_big));
+    EXPECT_EQ (-1, neg_really_big.cmp(slightly_bigger));
+    EXPECT_EQ (-3, neg_really_big.cmp(neg_not_as_big));
+    EXPECT_EQ (-3, neg_really_big.cmp(neg_a_little_smaller));
+    EXPECT_EQ (2, neg_really_big.cmp(neg_slightly_bigger));
+    EXPECT_EQ (3, neg_not_as_big.cmp(neg_really_big));
+    EXPECT_EQ (-2, neg_not_as_big.cmp(neg_a_little_smaller));
+    EXPECT_EQ (-3, neg_really_big.cmp(neg_a_little_smaller));
+
+    EXPECT_EQ (0, neg_really_big.cmp(QofInt128(barg, sarg, QofInt128::neg)));
+    EXPECT_EQ (0, really_big.cmp(QofInt128(barg, sarg)));
+    EXPECT_EQ (0, really_big.cmp(QofInt128(barg, sarg,  QofInt128::pos)));
+
+    EXPECT_EQ (0, really_big.cmp(-neg_really_big));
+    EXPECT_EQ (0, neg_really_big.cmp(-really_big));
+}
+
+TEST(qofint128_functions, stream_output)
+{
+    int64_t barg {INT64_C(567894392130486208)};
+    int64_t sarg {INT64_C(567894392130486207)};
+    int64_t nsarg {INT64_C(-567894392130486207)};
+
+    QofInt128 small (sarg);
+    QofInt128 neg_small (nsarg);
+
+    QofInt128 really_big (barg, sarg);
+    QofInt128 neg_really_big (barg, sarg, QofInt128::neg);
+
+    QofInt128 overflowed (INT64_C(0), INT64_C(0), QofInt128::overflow);
+    QofInt128 not_a_number (INT64_C(0), INT64_C(0), QofInt128::NaN);
+    QofInt128 boundary_value (UINT64_C(1), UINT64_MAX);
+
+    static const uint8_t char_buf_size {41};
+    char buf[char_buf_size] {};
+
+    EXPECT_STREQ("567894392130486207", small.asCharBufR (buf));
+    EXPECT_STREQ("-567894392130486207", neg_small.asCharBufR (buf));
+    EXPECT_STREQ("5237901256262967342410779070006542271", really_big.asCharBufR (buf));
+    EXPECT_STREQ("-5237901256262967342410779070006542271", neg_really_big.asCharBufR (buf));
+    EXPECT_STREQ("36893488147419103231", boundary_value.asCharBufR (buf));
+    EXPECT_STREQ("Overflow", overflowed.asCharBufR (buf));
+    EXPECT_STREQ("NaN", not_a_number.asCharBufR (buf));
+}
+
+TEST(qofint128_functions, add_and_subtract)
+{
+    /* UINT64_MAX = 18,446,744,073,709,551,615
+     * INT64_MAX  =  9,223,372,036,854,775,807
+     * barg + sarg = INT64_MAX
+     * barg + uarg = UINT64_MAX
+     */
+    int64_t barg {INT64_C(4878849681579065407)};
+    int64_t sarg {INT64_C(4344522355275710400)};
+    uint64_t uarg {UINT64_C(13567894392130486208)};
+
+    QofInt128 smallest (sarg + 100);
+    QofInt128 smaller (barg + 500);
+    QofInt128 small (uarg);
+    QofInt128 big (sarg, barg);
+    QofInt128 bigger (static_cast<uint64_t>(barg), uarg);
+    QofInt128 biggest (uarg, static_cast<uint64_t>(barg));
+
+    EXPECT_EQ (QofInt128(INT64_C(2), INT64_C(499)), small += smaller);
+    EXPECT_EQ (QofInt128(uarg), small -= smaller);
+    EXPECT_EQ (QofInt128(static_cast<uint64_t>(barg + sarg/2), UINT64_MAX),
+               bigger += big);
+    EXPECT_EQ (QofInt128(static_cast<uint64_t>(barg), uarg), bigger -= big);
+    bigger += biggest;
+    EXPECT_EQ (QofInt128(UINT64_MAX, UINT64_MAX), bigger);
+    bigger += smallest;
+    EXPECT_TRUE (bigger.isOverflow());
+    bigger -= biggest;
+    EXPECT_TRUE (bigger.isOverflow());
+ }
+

commit 9d029d7f821e36e6a0c4f05669ed035d1ade151e
Author: John Ralls <jralls at ceridwen.us>
Date:   Sat Sep 20 18:06:41 2014 -0700

    More realistic get_random_gnc_numeric()
    
    Increases the possible denominators to 1E10, but clamps the numerator to
    1E13 * denom with 1E19 max. This is equivalent to $1E8/1 US in
    Indonesian Rupiah, the currency with the lowest per-unit value in the
    world at the time of this commit.

diff --git a/src/engine/test-core/test-engine-stuff.c b/src/engine/test-core/test-engine-stuff.c
index d44c875..16ddc4d 100644
--- a/src/engine/test-core/test-engine-stuff.c
+++ b/src/engine/test-core/test-engine-stuff.c
@@ -421,7 +421,7 @@ get_random_gnc_numeric(void)
     }
     else
     {
-        gint64 norm = RAND_IN_RANGE (7ULL);
+        gint64 norm = RAND_IN_RANGE (11ULL);
 
         /* multiple of 10, between 1 and 1 million */
         deno = 1;
@@ -432,17 +432,27 @@ get_random_gnc_numeric(void)
         }
     }
 
-    /* Arbitrary random numbers can cause pointless overflow
-     * during calculations.  Limit dynamic range in hopes
-     * of avoiding overflow. Right now limit it to approx 2^44.
-     * The initial division is to help us down towards the range.
-     * The loop is to "make sure" we get there.  We might
-     * want to make this dependent on "deno" in the future.
-     */
-    numer = get_random_gint64 () % (2ULL << 44);
-    if (0 == numer) numer = 1;
     /* Make sure we have a non-zero denominator */
     if (0 == deno) deno = 1;
+
+    /* Arbitrary random numbers can cause pointless overflow during
+     * calculations.  Limit dynamic range to 1E18 because int64_t
+     * overflows before 1E19. The initial division is to help us down
+     * towards the range.  The loop is to "make sure" we get there.
+     * We might want to make this dependent on "deno" in the future.
+     */
+    static const int64_t num_limit = 10000000000000LL; //1E14
+    static const int64_t max_denom_mult = 1000000LL; //1E6
+    numer = get_random_gint64 ();
+    if (numer > num_limit * (deno > max_denom_mult ? max_denom_mult : deno))
+    {
+	int64_t num = numer % (num_limit * (deno > max_denom_mult ? max_denom_mult : deno));
+	if (num)
+	    numer = num;
+	else
+	    numer = num_limit * (deno > max_denom_mult ? max_denom_mult : deno);
+    }
+    if (0 == numer) numer = 1;
     return gnc_numeric_create(numer, deno);
 }
 

commit 996345a00f7f267ba404edda50cab359fd60666e
Author: John Ralls <jralls at ceridwen.us>
Date:   Wed Dec 3 16:24:16 2014 -0800

    Fix gperformance-tools setup and apply it to src/engine/tests.

diff --git a/configure.ac b/configure.ac
index 0324d9e..139c8e1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -757,7 +757,7 @@ enable_google_profile=no
 AC_ARG_ENABLE( google-profiler,
   [AS_HELP_STRING([--enable-google-profiler], [link in Google Performance Tools profiler; allows enabling profiling by setting $CPUPROFILE=/path/to/logfile.])],
   [AC_MSG_CHECKING([Google PerfTools Profiler])
-   AC_CHECK_LIB([profiler], [enable_google_profile=yes],
+   AC_CHECK_LIB([profiler], [ProfilerEnable], [enable_google_profile=yes],
       [AC_MSG_WARN([Google Profiling Enabled but the library was not found.])])
 ])
 AM_CONDITIONAL(WITH_GOOGLE_PROFILER, [test x$enable_google_profile = xyes])
diff --git a/src/engine/test/Makefile.am b/src/engine/test/Makefile.am
index 11c301f..3a5dccf 100644
--- a/src/engine/test/Makefile.am
+++ b/src/engine/test/Makefile.am
@@ -81,6 +81,10 @@ test_link_LDADD = ../libgncmod-engine.la \
   ${top_builddir}/src/libqof/qof/libgnc-qof.la \
   ${top_builddir}/src/core-utils/libgnc-core-utils.la
 
+if WITH_GOOGLE_PROFILER
+LDADD += -lprofiler
+endif
+
 EXTRA_DIST += \
   test-create-account \
   test-create-account.scm \



Summary of changes:
 configure.ac                                 |   2 +-
 po/POTFILES.in                               |   3 +-
 src/app-utils/gnc-ui-util.c                  |   4 +-
 src/app-utils/test/test-print-parse-amount.c |   2 +-
 src/backend/xml/test/test-dom-converters1.c  |   2 +-
 src/engine/Split.c                           |   9 +-
 src/engine/cap-gains.c                       |   3 +
 src/engine/gnc-lot.c                         |   1 +
 src/engine/test-core/test-engine-stuff.c     | 120 ++--
 src/engine/test-core/test-engine-stuff.h     |   2 +-
 src/engine/test/Makefile.am                  |   4 +
 src/engine/test/test-numeric.c               |  59 +-
 src/engine/test/utest-Split.cpp              |   7 +-
 src/engine/test/utest-Transaction.c          |   2 +-
 src/libqof/qof/Makefile.am                   |  13 +-
 src/libqof/qof/gnc-int128.cpp                | 923 +++++++++++++++++++++++++++
 src/libqof/qof/gnc-int128.hpp                | 254 ++++++++
 src/libqof/qof/gnc-numeric.cpp               | 756 +---------------------
 src/libqof/qof/gnc-numeric.h                 |   8 -
 src/libqof/qof/gnc-rational.cpp              | 351 ++++++++++
 src/libqof/qof/gnc-rational.hpp              |  87 +++
 src/libqof/qof/qofmath128-p.h                |  86 ---
 src/libqof/qof/qofmath128.cpp                | 418 ------------
 src/libqof/qof/test/Makefile.am              |  17 +
 src/libqof/qof/test/gtest-gnc-int128.cpp     | 467 ++++++++++++++
 25 files changed, 2281 insertions(+), 1319 deletions(-)
 create mode 100644 src/libqof/qof/gnc-int128.cpp
 create mode 100644 src/libqof/qof/gnc-int128.hpp
 create mode 100644 src/libqof/qof/gnc-rational.cpp
 create mode 100644 src/libqof/qof/gnc-rational.hpp
 delete mode 100644 src/libqof/qof/qofmath128-p.h
 delete mode 100644 src/libqof/qof/qofmath128.cpp
 create mode 100644 src/libqof/qof/test/gtest-gnc-int128.cpp



More information about the gnucash-changes mailing list