diff --git a/src/arith_uint256.cpp b/src/arith_uint256.cpp index b1dbb0788ed9..0646d783684b 100644 --- a/src/arith_uint256.cpp +++ b/src/arith_uint256.cpp @@ -5,6 +5,7 @@ #include +#include #include #include @@ -72,6 +73,23 @@ base_uint& base_uint::operator*=(const base_uint& b) return *this; } +template +base_uint& base_uint::operator/=(uint64_t b32) +{ + if (b32 == 0) + throw uint_error("Division by zero"); + if (b32 > std::numeric_limits::max()) { + return *this /= base_uint(b32); + } + uint64_t rem = 0; + for (int i = WIDTH - 1; i >= 0; --i) { + uint64_t cur = (rem << 32) | pn[i]; + pn[i] = static_cast(cur / b32); + rem = cur % b32; + } + return *this; +} + template base_uint& base_uint::operator/=(const base_uint& b) { diff --git a/src/arith_uint256.h b/src/arith_uint256.h index 009f939c1ac2..9f200915ee05 100644 --- a/src/arith_uint256.h +++ b/src/arith_uint256.h @@ -158,6 +158,7 @@ class base_uint base_uint& operator*=(uint32_t b32); base_uint& operator*=(const base_uint& b); + base_uint& operator/=(uint64_t b32); base_uint& operator/=(const base_uint& b); base_uint& operator++() @@ -207,6 +208,7 @@ class base_uint friend inline base_uint operator>>(const base_uint& a, int shift) { return base_uint(a) >>= shift; } friend inline base_uint operator<<(const base_uint& a, int shift) { return base_uint(a) <<= shift; } friend inline base_uint operator*(const base_uint& a, uint32_t b) { return base_uint(a) *= b; } + friend inline base_uint operator/(const base_uint& a, uint64_t b) { return base_uint(a) /= b; } friend inline bool operator==(const base_uint& a, const base_uint& b) { return memcmp(a.pn, b.pn, sizeof(a.pn)) == 0; } friend inline bool operator!=(const base_uint& a, const base_uint& b) { return memcmp(a.pn, b.pn, sizeof(a.pn)) != 0; } friend inline bool operator>(const base_uint& a, const base_uint& b) { return a.CompareTo(b) > 0; } diff --git a/src/test/arith_uint256_tests.cpp b/src/test/arith_uint256_tests.cpp index a3408a3fa99c..6f41c0167894 100644 --- a/src/test/arith_uint256_tests.cpp +++ b/src/test/arith_uint256_tests.cpp @@ -361,6 +361,19 @@ BOOST_AUTO_TEST_CASE( divide ) BOOST_CHECK(R2L / MaxL == ZeroL); BOOST_CHECK(MaxL / R2L == 1); BOOST_CHECK_THROW(R2L / ZeroL, uint_error); + + // The integer-divisor overload must be bit-identical to dividing by the same + // value widened to arith_uint256, for both the fast word-wise path + // (<= uint32 max) and the arith_uint256 fallback above it. + for (uint64_t d : {uint64_t{1}, uint64_t{2}, uint64_t{24}, uint64_t{3600}, + uint64_t{std::numeric_limits::max()}, + uint64_t{std::numeric_limits::max()} + 1, + uint64_t{0xFEDCBA9876543210}}) { + BOOST_CHECK(R1L / d == R1L / arith_uint256(d)); + BOOST_CHECK(R2L / d == R2L / arith_uint256(d)); + BOOST_CHECK(MaxL / d == MaxL / arith_uint256(d)); + } + BOOST_CHECK_THROW(R1L / uint64_t{0}, uint_error); }