Optimize uint128_t division by 10 within Number.cpp

* Optimization includes computing remainder from division.
* Used only within Number::operator*=.
This commit is contained in:
Howard Hinnant
2023-01-28 20:26:59 -05:00
committed by Elliot Lee
parent 6eaaa7bcfa
commit 2f1f453052
2 changed files with 34 additions and 3 deletions

View File

@@ -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)

View File

@@ -18,6 +18,7 @@
//==============================================================================
#include <ripple/basics/Number.h>
#include <boost/predef.h>
#include <algorithm>
#include <cassert>
#include <numeric>
@@ -335,6 +336,34 @@ Number::operator+=(Number const& y)
return *this;
}
// Optimization equivalent to:
// auto r = static_cast<unsigned>(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<unsigned>(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<unsigned>(zm % 10));
zm /= 10;
// The following is optimization for:
// g.push(static_cast<unsigned>(zm % 10));
// zm /= 10;
g.push(divu10(zm));
++ze;
}
xm = static_cast<rep>(zm);