From 2f1f453052088a2e49e725efb758962d3b9faa3f Mon Sep 17 00:00:00 2001 From: Howard Hinnant Date: Sat, 28 Jan 2023 20:26:59 -0500 Subject: [PATCH] Optimize uint128_t division by 10 within Number.cpp * Optimization includes computing remainder from division. * Used only within Number::operator*=. --- src/ripple/basics/impl/IOUAmount.cpp | 2 +- src/ripple/basics/impl/Number.cpp | 35 ++++++++++++++++++++++++++-- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/ripple/basics/impl/IOUAmount.cpp b/src/ripple/basics/impl/IOUAmount.cpp index 76f4bbe9fc..f011af19c0 100644 --- a/src/ripple/basics/impl/IOUAmount.cpp +++ b/src/ripple/basics/impl/IOUAmount.cpp @@ -53,7 +53,7 @@ IOUAmount::normalize() if (*stNumberSwitchover) { - Number v{mantissa_, exponent_}; + const Number v{mantissa_, exponent_}; mantissa_ = v.mantissa(); exponent_ = v.exponent(); if (exponent_ > maxExponent) diff --git a/src/ripple/basics/impl/Number.cpp b/src/ripple/basics/impl/Number.cpp index 52d2b556d4..9b3247536f 100644 --- a/src/ripple/basics/impl/Number.cpp +++ b/src/ripple/basics/impl/Number.cpp @@ -18,6 +18,7 @@ //============================================================================== #include +#include #include #include #include @@ -335,6 +336,34 @@ Number::operator+=(Number const& y) return *this; } +// Optimization equivalent to: +// auto r = static_cast(u % 10); +// u /= 10; +// return r; +// Derived from Hacker's Delight Second Edition Chapter 10 +// by Henry S. Warren, Jr. +static inline unsigned +divu10(uint128_t& u) +{ + // q = u * 0.75 + auto q = (u >> 1) + (u >> 2); + // iterate towards q = u * 0.8 + q += q >> 4; + q += q >> 8; + q += q >> 16; + q += q >> 32; + q += q >> 64; + // q /= 8 approximately == u / 10 + q >>= 3; + // r = u - q * 10 approximately == u % 10 + auto r = static_cast(u - ((q << 3) + (q << 1))); + // correction c is 1 if r >= 10 else 0 + auto c = (r + 6) >> 4; + u = q + c; + r -= c * 10; + return r; +} + Number& Number::operator*=(Number const& y) { @@ -370,8 +399,10 @@ Number::operator*=(Number const& y) g.set_negative(); while (zm > maxMantissa) { - g.push(static_cast(zm % 10)); - zm /= 10; + // The following is optimization for: + // g.push(static_cast(zm % 10)); + // zm /= 10; + g.push(divu10(zm)); ++ze; } xm = static_cast(zm);