diff --git a/extra/decimal_printer_lldb.py b/extra/decimal_printer_lldb.py index 95861ea6b..0748a308c 100644 --- a/extra/decimal_printer_lldb.py +++ b/extra/decimal_printer_lldb.py @@ -109,6 +109,26 @@ def decimal_fast128_summary(valobj, internal_dict): except Exception as e: return f"" +def u256_summary(valobj, internal_dict): + """ + Custom summary for u256 detail type + Displays in decimal notation + """ + + try: + val = valobj.GetNonSyntheticValue() + + bytes = val.GetChildMemberWithName("bytes") + b0 = bytes.GetChildAtIndex(0).GetValueAsUnsigned() + b1 = bytes.GetChildAtIndex(1).GetValueAsUnsigned() + b2 = bytes.GetChildAtIndex(2).GetValueAsUnsigned() + b3 = bytes.GetChildAtIndex(3).GetValueAsUnsigned() + + value = (b3 << 192) | (b2 << 128) | (b1 << 64) | b0 + return f"{value:,}" + except Exception as e: + return f"" + def __lldb_init_module(debugger, internal_dict): decimal32_pattern = r"^(const )?(boost::decimal::decimal32_t|(\w+::)*decimal32_t)( &| \*)?$" decimal64_pattern = r"^(const )?(boost::decimal::decimal64_t|(\w+::)*decimal64_t)( &| \*)?$" @@ -118,6 +138,8 @@ def __lldb_init_module(debugger, internal_dict): decimal_fast64_pattern = r"^(const )?(boost::decimal::decimal_fast64_t|(\w+::)*decimal_fast64_t)( &| \*)?$" decimal_fast128_pattern = r"^(const )?(boost::decimal::decimal_fast128_t|(\w+::)*decimal_fast128_t)( &| \*)?$" + u256_pattern = r"^(const )?(boost::decimal::detail::u256|(\w+::)*u256)( &| \*)?$" + debugger.HandleCommand( f'type summary add -x "{decimal32_pattern}" -e -F decimal_printer_lldb.decimal32_summary' ) @@ -172,6 +194,13 @@ def __lldb_init_module(debugger, internal_dict): print("decimal_fast128_t printer loaded successfully") + debugger.HandleCommand( + f'type summary add -x "{u256_pattern}" -e -F decimal_printer_lldb.u256_summary' + ) + debugger.HandleCommand( + f'type synthetic add -x "{u256_pattern}" -l decimal_printer_lldb.u256SyntheticProvider' + ) + class DecimalSyntheticProvider: def __init__(self, valobj, internal_dict): self.valobj = valobj @@ -228,3 +257,25 @@ def update(self): def has_children(self): return True +class u256SyntheticProvider: + def __init__(self, valobj, internal_dict): + self.valobj = valobj + + def num_children(self): + return 1 + + def get_child_index(self, name): + if name == "bytes": + return 0 + return -1 + + def get_child_at_index(self, index): + if index == 0: + return self.valobj.GetChildMemberWithName("bytes") + return None + + def update(self): + pass + + def has_children(self): + return True diff --git a/include/boost/decimal/decimal128_t.hpp b/include/boost/decimal/decimal128_t.hpp index dba59a6de..b8ce1669e 100644 --- a/include/boost/decimal/decimal128_t.hpp +++ b/include/boost/decimal/decimal128_t.hpp @@ -1708,17 +1708,10 @@ constexpr auto operator+(const decimal128_t& lhs, const decimal128_t& rhs) noexc } #endif - auto lhs_sig {lhs.full_significand()}; - auto lhs_exp {lhs.biased_exponent()}; - detail::expand_significand(lhs_sig, lhs_exp); - - auto rhs_sig {rhs.full_significand()}; - auto rhs_exp {rhs.biased_exponent()}; - detail::expand_significand(rhs_sig, rhs_exp); + const auto lhs_components {lhs.to_components()}; + const auto rhs_components {rhs.to_components()}; - return detail::d128_add_impl(lhs_sig, lhs_exp, lhs.isneg(), - rhs_sig, rhs_exp, rhs.isneg(), - abs(lhs) > abs(rhs)); + return detail::d128_add_impl_new(lhs_components, rhs_components); } template diff --git a/include/boost/decimal/detail/add_impl.hpp b/include/boost/decimal/detail/add_impl.hpp index 8eb1d0ce3..b3a51d2ae 100644 --- a/include/boost/decimal/detail/add_impl.hpp +++ b/include/boost/decimal/detail/add_impl.hpp @@ -12,6 +12,7 @@ #include #include #include +#include #include "int128.hpp" #ifndef BOOST_DECIMAL_BUILD_MODULE @@ -188,6 +189,191 @@ constexpr auto add_impl(const T& lhs, const T& rhs) noexcept -> ReturnType return ReturnType{return_sig, lhs_exp, new_sig < 0}; } +template +constexpr auto d128_add_impl_new(const T& lhs, const T& rhs) noexcept -> ReturnType +{ + using promoted_sig_type = u256; + + auto big_lhs {lhs.full_significand()}; + auto big_rhs {rhs.full_significand()}; + auto lhs_exp {lhs.biased_exponent()}; + auto rhs_exp {rhs.biased_exponent()}; + promoted_sig_type promoted_lhs {big_lhs}; + promoted_sig_type promoted_rhs {big_rhs}; + + // Align to larger exponent + if (lhs_exp != rhs_exp) + { + constexpr auto max_shift {detail::make_positive_unsigned(std::numeric_limits::digits10 - detail::precision_v - 1)}; + const auto shift {detail::make_positive_unsigned(lhs_exp - rhs_exp)}; + + if (shift > max_shift) + { + auto round {_boost_decimal_global_rounding_mode}; + + #ifndef BOOST_DECIMAL_NO_CONSTEVAL_DETECTION + + if (!BOOST_DECIMAL_IS_CONSTANT_EVALUATED(lhs)) + { + round = fegetround(); + } + + #endif + + if (BOOST_DECIMAL_LIKELY(round != rounding_mode::fe_dec_downward && round != rounding_mode::fe_dec_upward)) + { + return big_lhs != 0U && (lhs_exp > rhs_exp) ? + ReturnType{lhs.full_significand(), lhs.biased_exponent(), lhs.isneg()} : + ReturnType{rhs.full_significand(), rhs.biased_exponent(), rhs.isneg()}; + } + else if (round == rounding_mode::fe_dec_downward) + { + // If we are subtracting even disparate numbers we need to round down + // E.g. "5e+95"_DF - "4e-100"_DF == "4.999999e+95"_DF + const auto use_lhs {big_lhs != 0U && (lhs_exp > rhs_exp)}; + + // Need to check for the case where we have 1e+95 - anything = 9.99999... without losing a nine + if (use_lhs) + { + if (big_rhs != 0U && (lhs.isneg() != rhs.isneg())) + { + if (is_power_of_10(big_lhs)) + { + --big_lhs; + big_lhs *= 10U; + big_lhs += 9U; + --lhs_exp; + } + else + { + --big_lhs; + } + } + + return ReturnType{big_lhs, lhs_exp, lhs.isneg()}; + } + else + { + if (big_lhs != 0U && (lhs.isneg() != rhs.isneg())) + { + if (is_power_of_10(big_rhs)) + { + --big_rhs; + big_rhs *= 10U; + big_rhs += 9U; + --rhs_exp; + } + else + { + --big_rhs; + } + } + + return ReturnType{big_rhs, rhs_exp, rhs.isneg()}; + } + } + else + { + // rounding mode == fe_dec_upward + // Unconditionally round up. Could be 5e+95 + 4e-100 -> 5.000001e+95 + const bool use_lhs {big_lhs != 0U && (lhs_exp > rhs_exp)}; + + if (use_lhs) + { + if (big_rhs != 0U) + { + if (lhs.isneg() != rhs.isneg()) + { + if (is_power_of_10(big_lhs)) + { + --big_lhs; + big_lhs *= 10U; + big_lhs += 9U; + --lhs_exp; + } + else + { + --big_lhs; + } + } + else + { + ++big_lhs; + } + } + + return ReturnType{big_lhs, lhs_exp, lhs.isneg()} ; + } + else + { + if (big_lhs != 0U) + { + if (rhs.isneg() != lhs.isneg()) + { + --big_rhs; + big_rhs *= 10U; + big_rhs += 9U; + --rhs_exp; + } + else + { + ++big_rhs; + } + } + + return ReturnType{big_rhs, rhs_exp, rhs.isneg()}; + } + } + } + + if (lhs_exp < rhs_exp) + { + promoted_rhs *= detail::pow10(shift); + lhs_exp = rhs_exp - static_cast(shift); + } + else + { + const auto shift_pow10 {detail::pow10(static_cast(shift))}; + promoted_lhs *= shift_pow10; + lhs_exp -= static_cast(shift); + } + } + + u256 return_sig {}; + bool return_sign {}; + const auto lhs_sign {lhs.isneg()}; + const auto rhs_sign {rhs.isneg()}; + + if (lhs_sign && !rhs_sign) + { + // -lhs + rhs = rhs - lhs + return_sign = i256_sub(promoted_rhs, promoted_lhs, return_sig); + } + else if (!lhs_sign && rhs_sign) + { + // lhs - rhs + return_sign = i256_sub(promoted_lhs, promoted_rhs, return_sig); + } + else + { + // lhs + rhs or -lhs + -rhs + return_sig = promoted_lhs + promoted_rhs; + return_sign = lhs_sign && rhs_sign; + } + + BOOST_DECIMAL_IF_CONSTEXPR (detail::decimal_val_v == 128) + { + // In the regular 128-bit case there's a chance the high words are empty, + // and we can just convert to 128-bit arithmetic now + if (return_sig[2] == 0U && return_sig[3] == 0U) + { + return ReturnType{static_cast(return_sig), lhs_exp, return_sign}; + } + } + + return ReturnType{return_sig, lhs_exp, return_sign}; +} + template constexpr auto d128_add_impl(T lhs_sig, U lhs_exp, bool lhs_sign, T rhs_sig, U rhs_exp, bool rhs_sign, diff --git a/include/boost/decimal/detail/config.hpp b/include/boost/decimal/detail/config.hpp index 3855e7a62..aad650b84 100644 --- a/include/boost/decimal/detail/config.hpp +++ b/include/boost/decimal/detail/config.hpp @@ -97,8 +97,10 @@ # endif # if defined(__ADX__) && defined(BOOST_DECIMAL_HAS_MSVC_64BIT_INTRINSICS) # define BOOST_DECIMAL_ADD_CARRY _addcarryx_u64 +# define BOOST_DECIMAL_SUB_BORROW _subborrow_u64 # elif defined(BOOST_DECIMAL_HAS_MSVC_64BIT_INTRINSICS) # define BOOST_DECIMAL_ADD_CARRY _addcarry_u64 +# define BOOST_DECIMAL_SUB_BORROW _subborrow_u64 # endif #elif defined(__x86_64__) # ifndef BOOST_DECIMAL_BUILD_MODULE @@ -107,8 +109,10 @@ # define BOOST_DECIMAL_HAS_X64_INTRINSICS # ifdef __ADX__ # define BOOST_DECIMAL_ADD_CARRY _addcarryx_u64 +# define BOOST_DECIMAL_SUB_BORROW _subborrow_u64 # else # define BOOST_DECIMAL_ADD_CARRY _addcarry_u64 +# define BOOST_DECIMAL_SUB_BORROW _subborrow_u64 # endif #elif defined(__ARM_NEON__) # ifndef BOOST_DECIMAL_BUILD_MODULE diff --git a/include/boost/decimal/detail/i256.hpp b/include/boost/decimal/detail/i256.hpp new file mode 100644 index 000000000..8620df64e --- /dev/null +++ b/include/boost/decimal/detail/i256.hpp @@ -0,0 +1,234 @@ +// Copyright 2023 - 2025 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt +// +// This is not a fully featured implementation of a 256-bit integer like int128::uint128_t is +// i256 only contains the minimum amount that we need to perform operations like decimal128_t add/sub + +#ifndef BOOST_DECIMAL_DETAIL_I256_HPP +#define BOOST_DECIMAL_DETAIL_I256_HPP + +#include +#include +#include + +namespace boost { +namespace decimal { +namespace detail { + +namespace impl { + +// This impl works regardless of intrinsics or otherwise +constexpr u256 u256_add_impl(const int128::uint128_t& lhs, const int128::uint128_t& rhs) noexcept +{ + u256 result; + std::uint64_t carry {}; + + auto sum {lhs.low + rhs.low}; + result[0] = sum; + carry = (sum < lhs.low) ? 1 : 0; + + sum = lhs.high + rhs.high + carry; + result[1] = sum; + result[2] = static_cast(sum < lhs.high || (sum == lhs.high && carry)); + + return result; +} + +} // namespace impl + +#if !defined(BOOST_DECIMAL_NO_CONSTEVAL_DETECTION) && defined(BOOST_DECIMAL_ADD_CARRY) + +constexpr u256 u256_add(const int128::uint128_t& lhs, const int128::uint128_t& rhs) noexcept +{ + if (BOOST_DECIMAL_IS_CONSTANT_EVALUATED(lhs)) + { + return impl::u256_add_impl(lhs, rhs); + } + else + { + unsigned long long result[3] {}; + unsigned char carry {}; + carry = BOOST_DECIMAL_ADD_CARRY(carry, lhs.low, rhs.low, &result[0]); + result[2] = static_cast(BOOST_DECIMAL_ADD_CARRY(carry, lhs.high, rhs.high, &result[1])); + + return {UINT64_C(0), result[2], result[1], result[0]}; + } +} + +#elif !defined(BOOST_DECIMAL_NO_CONSTEVAL_DETECTION) && defined(__GNUC__) && !defined(BOOST_DECIMAL_ADD_CARRY) + +constexpr u256 u256_add(const int128::uint128_t& lhs, const int128::uint128_t& rhs) noexcept +{ + if (BOOST_DECIMAL_IS_CONSTANT_EVALUATED(lhs)) + { + return impl::u256_add_impl(lhs, rhs); + } + else + { + unsigned long long result[3] {}; + bool carry {}; + carry = impl::add_carry_u64(carry, lhs.low, rhs.low, &result[0]); + result[2] = static_cast(impl::add_carry_u64(carry, lhs.high, rhs.high, &result[1])); + + return {UINT64_C(0), result[2], result[1], result[0]}; + } +} + +#endif + +namespace impl { + +constexpr std::uint64_t sub_borrow_u64(const std::uint64_t borrow_in, const std::uint64_t a, const std::uint64_t b, std::uint64_t& result) noexcept +{ + const auto diff {a - b}; + const auto b1 {static_cast(a < b)}; + result = diff - borrow_in; + const auto borrow_out {b1 | (diff < borrow_in)}; + + return borrow_out; +} + +constexpr bool i256_sub_impl(const int128::uint128_t& a, const int128::uint128_t& b, u256& result) noexcept +{ + if (a >= b) + { + std::uint64_t borrow {}; + result[0] = sub_borrow_u64(0, a.low, b.low, borrow); + result[1] = sub_borrow_u64(borrow, a.high, b.high, borrow); + + return false; + } + else + { + // a < b: negative result, |a - b| = b - a + std::uint64_t borrow {}; + result[0] = sub_borrow_u64(0, b.low, a.low, borrow); + result[1] = sub_borrow_u64(borrow, a.high, b.high, borrow); + + return true; + } +} + +constexpr bool i256_sub_impl(const u256& a, const u256& b, u256& result) noexcept +{ + if (a >= b) + { + auto borrow {impl::sub_borrow_u64(0, a[3], b[3], result[3])}; + borrow = impl::sub_borrow_u64(borrow, a[2], b[2], result[2]); + borrow = impl::sub_borrow_u64(borrow, a[1], b[1], result[1]); + impl::sub_borrow_u64(borrow, a[0], b[0], result[0]); + return false; + } + else + { + // a < b: negative result, |a - b| = b - a + auto borrow {impl::sub_borrow_u64(0, b[3], a[3], result[3])}; + borrow = impl::sub_borrow_u64(borrow, b[2], a[2], result[2]); + borrow = impl::sub_borrow_u64(borrow, b[1], a[1], result[1]); + impl::sub_borrow_u64(borrow, b[0], a[0], result[0]); + return true; + } +} + +} // namespace impl + +constexpr bool i256_sub(const int128::uint128_t& a, const int128::uint128_t& b, u256& result) noexcept +{ + return impl::i256_sub_impl(a, b, result); +} + +#if !defined(BOOST_DECIMAL_NO_CONSTEVAL_DETECTION) && defined(BOOST_DECIMAL_ADD_CARRY) + +constexpr bool i256_sub(const u256& a, const u256& b, u256& res) noexcept +{ + if (BOOST_DECIMAL_IS_CONSTANT_EVALUATED(lhs)) + { + return impl::i256_sub_impl(a, b, res); + } + else + { + if (a >= b) + { + unsigned long long result[4] {}; + unsigned char borrow {}; + + borrow = BOOST_DECIMAL_SUB_BORROW(borrow, a[3], b[3], &result[3]); + borrow = BOOST_DECIMAL_SUB_BORROW(borrow, a[2], b[2], &result[2]); + borrow = BOOST_DECIMAL_SUB_BORROW(borrow, a[1], b[1], &result[1]); + BOOST_DECIMAL_SUB_BORROW(borrow, a[0], b[0], &result[0]); + + res = u256{result[3], result[2], result[1], result[0]}; + return false; + } + else + { + unsigned long long result[4] {}; + unsigned char borrow {}; + + borrow = BOOST_DECIMAL_SUB_BORROW(borrow, b[3], a[3], &result[3]); + borrow = BOOST_DECIMAL_SUB_BORROW(borrow, b[2], a[2], &result[2]); + borrow = BOOST_DECIMAL_SUB_BORROW(borrow, b[1], a[1], &result[1]); + BOOST_DECIMAL_SUB_BORROW(borrow, b[0], a[0], &result[0]); + + res = u256{result[3], result[2], result[1], result[0]}; + return true; + } + } +} + +#elif !defined(BOOST_DECIMAL_NO_CONSTEVAL_DETECTION) && defined(__GNUC__) && !defined(BOOST_DECIMAL_ADD_CARRY) + +namespace impl { + +inline bool sub_borrow_u64_intrin(const bool borrow_in, const std::uint64_t a, const std::uint64_t b, std::uint64_t& diff) noexcept { + unsigned long long res; + auto c = __builtin_usubll_overflow(a, b, &res); + c |= __builtin_usubll_overflow(res, static_cast(borrow_in), &res); + diff = res; + + return c; +} + +} // namespace impl + +constexpr bool i256_sub(const u256& a, const u256& b, u256& result) noexcept +{ + if (BOOST_DECIMAL_IS_CONSTANT_EVALUATED(lhs)) + { + return impl::i256_sub_impl(a, b, result); + } + else + { + if (a >= b) + { + bool borrow {}; + + borrow = impl::sub_borrow_u64_intrin(borrow, a[3], b[3], result[3]); + borrow = impl::sub_borrow_u64_intrin(borrow, a[2], b[2], result[2]); + borrow = impl::sub_borrow_u64_intrin(borrow, a[1], b[1], result[1]); + impl::sub_borrow_u64_intrin(borrow, a[0], b[0], result[0]); + + return false; + } + else + { + bool borrow {}; + + borrow = impl::sub_borrow_u64_intrin(borrow, b[3], a[3], result[3]); + borrow = impl::sub_borrow_u64_intrin(borrow, b[2], a[2], result[2]); + borrow = impl::sub_borrow_u64_intrin(borrow, b[1], a[1], result[1]); + impl::sub_borrow_u64_intrin(borrow, b[0], a[0], result[0]); + + return true; + } + } +} + +#endif + +} // namespace detail +} // namespace decimal +} // namespace boost + +#endif // BOOST_DECIMAL_DETAIL_I256_HPP diff --git a/include/boost/decimal/detail/power_tables.hpp b/include/boost/decimal/detail/power_tables.hpp index 327d5cd3d..36c62f362 100644 --- a/include/boost/decimal/detail/power_tables.hpp +++ b/include/boost/decimal/detail/power_tables.hpp @@ -124,84 +124,86 @@ BOOST_DECIMAL_INLINE_CONSTEXPR_VARIABLE detail::builtin_uint128_t builtin_128_po #endif -BOOST_DECIMAL_INLINE_CONSTEXPR_VARIABLE u256 u256_pow_10[78] = { - u256{BOOST_DECIMAL_DETAIL_INT128_pow10[0]}, - u256{BOOST_DECIMAL_DETAIL_INT128_pow10[1]}, - u256{BOOST_DECIMAL_DETAIL_INT128_pow10[2]}, - u256{BOOST_DECIMAL_DETAIL_INT128_pow10[3]}, - u256{BOOST_DECIMAL_DETAIL_INT128_pow10[4]}, - u256{BOOST_DECIMAL_DETAIL_INT128_pow10[5]}, - u256{BOOST_DECIMAL_DETAIL_INT128_pow10[6]}, - u256{BOOST_DECIMAL_DETAIL_INT128_pow10[7]}, - u256{BOOST_DECIMAL_DETAIL_INT128_pow10[8]}, - u256{BOOST_DECIMAL_DETAIL_INT128_pow10[9]}, - u256{BOOST_DECIMAL_DETAIL_INT128_pow10[10]}, - u256{BOOST_DECIMAL_DETAIL_INT128_pow10[11]}, - u256{BOOST_DECIMAL_DETAIL_INT128_pow10[12]}, - u256{BOOST_DECIMAL_DETAIL_INT128_pow10[13]}, - u256{BOOST_DECIMAL_DETAIL_INT128_pow10[14]}, - u256{BOOST_DECIMAL_DETAIL_INT128_pow10[15]}, - u256{BOOST_DECIMAL_DETAIL_INT128_pow10[16]}, - u256{BOOST_DECIMAL_DETAIL_INT128_pow10[17]}, - u256{BOOST_DECIMAL_DETAIL_INT128_pow10[18]}, - u256{BOOST_DECIMAL_DETAIL_INT128_pow10[19]}, - u256{BOOST_DECIMAL_DETAIL_INT128_pow10[20]}, - u256{BOOST_DECIMAL_DETAIL_INT128_pow10[21]}, - u256{BOOST_DECIMAL_DETAIL_INT128_pow10[22]}, - u256{BOOST_DECIMAL_DETAIL_INT128_pow10[23]}, - u256{BOOST_DECIMAL_DETAIL_INT128_pow10[24]}, - u256{BOOST_DECIMAL_DETAIL_INT128_pow10[25]}, - u256{BOOST_DECIMAL_DETAIL_INT128_pow10[26]}, - u256{BOOST_DECIMAL_DETAIL_INT128_pow10[27]}, - u256{BOOST_DECIMAL_DETAIL_INT128_pow10[28]}, - u256{BOOST_DECIMAL_DETAIL_INT128_pow10[29]}, - u256{BOOST_DECIMAL_DETAIL_INT128_pow10[30]}, - u256{BOOST_DECIMAL_DETAIL_INT128_pow10[31]}, - u256{BOOST_DECIMAL_DETAIL_INT128_pow10[32]}, - u256{BOOST_DECIMAL_DETAIL_INT128_pow10[33]}, - u256{BOOST_DECIMAL_DETAIL_INT128_pow10[34]}, - u256{BOOST_DECIMAL_DETAIL_INT128_pow10[35]}, - u256{BOOST_DECIMAL_DETAIL_INT128_pow10[36]}, - u256{BOOST_DECIMAL_DETAIL_INT128_pow10[37]}, - u256{BOOST_DECIMAL_DETAIL_INT128_pow10[38]}, - umul256(BOOST_DECIMAL_DETAIL_INT128_pow10[38], BOOST_DECIMAL_DETAIL_INT128_pow10[1]), - umul256(BOOST_DECIMAL_DETAIL_INT128_pow10[38], BOOST_DECIMAL_DETAIL_INT128_pow10[2]), - umul256(BOOST_DECIMAL_DETAIL_INT128_pow10[38], BOOST_DECIMAL_DETAIL_INT128_pow10[3]), - umul256(BOOST_DECIMAL_DETAIL_INT128_pow10[38], BOOST_DECIMAL_DETAIL_INT128_pow10[4]), - umul256(BOOST_DECIMAL_DETAIL_INT128_pow10[38], BOOST_DECIMAL_DETAIL_INT128_pow10[5]), - umul256(BOOST_DECIMAL_DETAIL_INT128_pow10[38], BOOST_DECIMAL_DETAIL_INT128_pow10[6]), - umul256(BOOST_DECIMAL_DETAIL_INT128_pow10[38], BOOST_DECIMAL_DETAIL_INT128_pow10[7]), - umul256(BOOST_DECIMAL_DETAIL_INT128_pow10[38], BOOST_DECIMAL_DETAIL_INT128_pow10[8]), - umul256(BOOST_DECIMAL_DETAIL_INT128_pow10[38], BOOST_DECIMAL_DETAIL_INT128_pow10[9]), - umul256(BOOST_DECIMAL_DETAIL_INT128_pow10[38], BOOST_DECIMAL_DETAIL_INT128_pow10[10]), - umul256(BOOST_DECIMAL_DETAIL_INT128_pow10[38], BOOST_DECIMAL_DETAIL_INT128_pow10[11]), - umul256(BOOST_DECIMAL_DETAIL_INT128_pow10[38], BOOST_DECIMAL_DETAIL_INT128_pow10[12]), - umul256(BOOST_DECIMAL_DETAIL_INT128_pow10[38], BOOST_DECIMAL_DETAIL_INT128_pow10[13]), - umul256(BOOST_DECIMAL_DETAIL_INT128_pow10[38], BOOST_DECIMAL_DETAIL_INT128_pow10[14]), - umul256(BOOST_DECIMAL_DETAIL_INT128_pow10[38], BOOST_DECIMAL_DETAIL_INT128_pow10[15]), - umul256(BOOST_DECIMAL_DETAIL_INT128_pow10[38], BOOST_DECIMAL_DETAIL_INT128_pow10[16]), - umul256(BOOST_DECIMAL_DETAIL_INT128_pow10[38], BOOST_DECIMAL_DETAIL_INT128_pow10[17]), - umul256(BOOST_DECIMAL_DETAIL_INT128_pow10[38], BOOST_DECIMAL_DETAIL_INT128_pow10[18]), - umul256(BOOST_DECIMAL_DETAIL_INT128_pow10[38], BOOST_DECIMAL_DETAIL_INT128_pow10[19]), - umul256(BOOST_DECIMAL_DETAIL_INT128_pow10[38], BOOST_DECIMAL_DETAIL_INT128_pow10[20]), - umul256(BOOST_DECIMAL_DETAIL_INT128_pow10[38], BOOST_DECIMAL_DETAIL_INT128_pow10[21]), - umul256(BOOST_DECIMAL_DETAIL_INT128_pow10[38], BOOST_DECIMAL_DETAIL_INT128_pow10[22]), - umul256(BOOST_DECIMAL_DETAIL_INT128_pow10[38], BOOST_DECIMAL_DETAIL_INT128_pow10[23]), - umul256(BOOST_DECIMAL_DETAIL_INT128_pow10[38], BOOST_DECIMAL_DETAIL_INT128_pow10[24]), - umul256(BOOST_DECIMAL_DETAIL_INT128_pow10[38], BOOST_DECIMAL_DETAIL_INT128_pow10[25]), - umul256(BOOST_DECIMAL_DETAIL_INT128_pow10[38], BOOST_DECIMAL_DETAIL_INT128_pow10[26]), - umul256(BOOST_DECIMAL_DETAIL_INT128_pow10[38], BOOST_DECIMAL_DETAIL_INT128_pow10[27]), - umul256(BOOST_DECIMAL_DETAIL_INT128_pow10[38], BOOST_DECIMAL_DETAIL_INT128_pow10[28]), - umul256(BOOST_DECIMAL_DETAIL_INT128_pow10[38], BOOST_DECIMAL_DETAIL_INT128_pow10[29]), - umul256(BOOST_DECIMAL_DETAIL_INT128_pow10[38], BOOST_DECIMAL_DETAIL_INT128_pow10[30]), - umul256(BOOST_DECIMAL_DETAIL_INT128_pow10[38], BOOST_DECIMAL_DETAIL_INT128_pow10[31]), - umul256(BOOST_DECIMAL_DETAIL_INT128_pow10[38], BOOST_DECIMAL_DETAIL_INT128_pow10[32]), - umul256(BOOST_DECIMAL_DETAIL_INT128_pow10[38], BOOST_DECIMAL_DETAIL_INT128_pow10[33]), - umul256(BOOST_DECIMAL_DETAIL_INT128_pow10[38], BOOST_DECIMAL_DETAIL_INT128_pow10[34]), - umul256(BOOST_DECIMAL_DETAIL_INT128_pow10[38], BOOST_DECIMAL_DETAIL_INT128_pow10[35]), - umul256(BOOST_DECIMAL_DETAIL_INT128_pow10[38], BOOST_DECIMAL_DETAIL_INT128_pow10[36]), - umul256(BOOST_DECIMAL_DETAIL_INT128_pow10[38], BOOST_DECIMAL_DETAIL_INT128_pow10[37]), - umul256(BOOST_DECIMAL_DETAIL_INT128_pow10[38], BOOST_DECIMAL_DETAIL_INT128_pow10[38]) +BOOST_DECIMAL_INLINE_CONSTEXPR_VARIABLE u256 u256_pow_10[79] = { + u256{UINT64_C(0), UINT64_C(0), UINT64_C(0), UINT64_C(1)}, + u256{UINT64_C(0), UINT64_C(0), UINT64_C(0), UINT64_C(10)}, + u256{UINT64_C(0), UINT64_C(0), UINT64_C(0), UINT64_C(100)}, + u256{UINT64_C(0), UINT64_C(0), UINT64_C(0), UINT64_C(1000)}, + u256{UINT64_C(0), UINT64_C(0), UINT64_C(0), UINT64_C(10000)}, + u256{UINT64_C(0), UINT64_C(0), UINT64_C(0), UINT64_C(100000)}, + u256{UINT64_C(0), UINT64_C(0), UINT64_C(0), UINT64_C(1000000)}, + u256{UINT64_C(0), UINT64_C(0), UINT64_C(0), UINT64_C(10000000)}, + u256{UINT64_C(0), UINT64_C(0), UINT64_C(0), UINT64_C(100000000)}, + u256{UINT64_C(0), UINT64_C(0), UINT64_C(0), UINT64_C(1000000000)}, + u256{UINT64_C(0), UINT64_C(0), UINT64_C(0), UINT64_C(10000000000)}, + u256{UINT64_C(0), UINT64_C(0), UINT64_C(0), UINT64_C(100000000000)}, + u256{UINT64_C(0), UINT64_C(0), UINT64_C(0), UINT64_C(1000000000000)}, + u256{UINT64_C(0), UINT64_C(0), UINT64_C(0), UINT64_C(10000000000000)}, + u256{UINT64_C(0), UINT64_C(0), UINT64_C(0), UINT64_C(100000000000000)}, + u256{UINT64_C(0), UINT64_C(0), UINT64_C(0), UINT64_C(1000000000000000)}, + u256{UINT64_C(0), UINT64_C(0), UINT64_C(0), UINT64_C(10000000000000000)}, + u256{UINT64_C(0), UINT64_C(0), UINT64_C(0), UINT64_C(100000000000000000)}, + u256{UINT64_C(0), UINT64_C(0), UINT64_C(0), UINT64_C(1000000000000000000)}, + u256{UINT64_C(0), UINT64_C(0), UINT64_C(0), UINT64_C(10000000000000000000)}, + u256{UINT64_C(0), UINT64_C(0), UINT64_C(5), UINT64_C(7766279631452241920)}, + u256{UINT64_C(0), UINT64_C(0), UINT64_C(54), UINT64_C(3875820019684212736)}, + u256{UINT64_C(0), UINT64_C(0), UINT64_C(542), UINT64_C(1864712049423024128)}, + u256{UINT64_C(0), UINT64_C(0), UINT64_C(5421), UINT64_C(200376420520689664)}, + u256{UINT64_C(0), UINT64_C(0), UINT64_C(54210), UINT64_C(2003764205206896640)}, + u256{UINT64_C(0), UINT64_C(0), UINT64_C(542101), UINT64_C(1590897978359414784)}, + u256{UINT64_C(0), UINT64_C(0), UINT64_C(5421010), UINT64_C(15908979783594147840)}, + u256{UINT64_C(0), UINT64_C(0), UINT64_C(54210108), UINT64_C(11515845246265065472)}, + u256{UINT64_C(0), UINT64_C(0), UINT64_C(542101086), UINT64_C(4477988020393345024)}, + u256{UINT64_C(0), UINT64_C(0), UINT64_C(5421010862), UINT64_C(7886392056514347008)}, + u256{UINT64_C(0), UINT64_C(0), UINT64_C(54210108624), UINT64_C(5076944270305263616)}, + u256{UINT64_C(0), UINT64_C(0), UINT64_C(542101086242), UINT64_C(13875954555633532928)}, + u256{UINT64_C(0), UINT64_C(0), UINT64_C(5421010862427), UINT64_C(9632337040368467968)}, + u256{UINT64_C(0), UINT64_C(0), UINT64_C(54210108624275), UINT64_C(4089650035136921600)}, + u256{UINT64_C(0), UINT64_C(0), UINT64_C(542101086242752), UINT64_C(4003012203950112768)}, + u256{UINT64_C(0), UINT64_C(0), UINT64_C(5421010862427522), UINT64_C(3136633892082024448)}, + u256{UINT64_C(0), UINT64_C(0), UINT64_C(54210108624275221), UINT64_C(12919594847110692864)}, + u256{UINT64_C(0), UINT64_C(0), UINT64_C(542101086242752217), UINT64_C(68739955140067328)}, + u256{UINT64_C(0), UINT64_C(0), UINT64_C(5421010862427522170), UINT64_C(687399551400673280)}, + u256{UINT64_C(0), UINT64_C(2), UINT64_C(17316620476856118468), UINT64_C(6873995514006732800)}, + u256{UINT64_C(0), UINT64_C(29), UINT64_C(7145508105175220139), UINT64_C(13399722918938673152)}, + u256{UINT64_C(0), UINT64_C(293), UINT64_C(16114848830623546549), UINT64_C(4870020673419870208)}, + u256{UINT64_C(0), UINT64_C(2938), UINT64_C(13574535716559052564), UINT64_C(11806718586779598848)}, + u256{UINT64_C(0), UINT64_C(29387), UINT64_C(6618148649623664334), UINT64_C(7386721425538678784)}, + u256{UINT64_C(0), UINT64_C(293873), UINT64_C(10841254275107988496), UINT64_C(80237960548581376)}, + u256{UINT64_C(0), UINT64_C(2938735), UINT64_C(16178822382532126880), UINT64_C(802379605485813760)}, + u256{UINT64_C(0), UINT64_C(29387358), UINT64_C(14214271235644855872), UINT64_C(8023796054858137600)}, + u256{UINT64_C(0), UINT64_C(293873587), UINT64_C(13015503840481697412), UINT64_C(6450984253743169536)}, + u256{UINT64_C(0), UINT64_C(2938735877), UINT64_C(1027829888850112811), UINT64_C(9169610316303040512)}, + u256{UINT64_C(0), UINT64_C(29387358770), UINT64_C(10278298888501128114), UINT64_C(17909126868192198656)}, + u256{UINT64_C(0), UINT64_C(293873587705), UINT64_C(10549268516463523069), UINT64_C(13070572018536022016)}, + u256{UINT64_C(0), UINT64_C(2938735877055), UINT64_C(13258964796087472617), UINT64_C(1578511669393358848)}, + u256{UINT64_C(0), UINT64_C(29387358770557), UINT64_C(3462439444907864858), UINT64_C(15785116693933588480)}, + u256{UINT64_C(0), UINT64_C(293873587705571), UINT64_C(16177650375369096972), UINT64_C(10277214349659471872)}, + u256{UINT64_C(0), UINT64_C(2938735877055718), UINT64_C(14202551164014556797), UINT64_C(10538423128046960640)}, + u256{UINT64_C(0), UINT64_C(29387358770557187), UINT64_C(12898303124178706663), UINT64_C(13150510911921848320)}, + u256{UINT64_C(0), UINT64_C(293873587705571876), UINT64_C(18302566799529756941), UINT64_C(2377900603251621888)}, + u256{UINT64_C(0), UINT64_C(2938735877055718769), UINT64_C(17004971331911604867), UINT64_C(5332261958806667264)}, + u256{UINT64_C(1), UINT64_C(10940614696847636083), UINT64_C(4029016655730084128), UINT64_C(16429131440647569408)}, + u256{UINT64_C(15), UINT64_C(17172426599928602752), UINT64_C(3396678409881738056), UINT64_C(16717361816799281152)}, + u256{UINT64_C(159), UINT64_C(5703569335900062977), UINT64_C(15520040025107828953), UINT64_C(1152921504606846976)}, + u256{UINT64_C(1593), UINT64_C(1695461137871974930), UINT64_C(7626447661401876602), UINT64_C(11529215046068469760)}, + u256{UINT64_C(15930), UINT64_C(16954611378719749304), UINT64_C(2477500319180559562), UINT64_C(4611686018427387904)}, + u256{UINT64_C(159309), UINT64_C(3525417123811528497), UINT64_C(6328259118096044006), UINT64_C(9223372036854775808)}, + u256{UINT64_C(1593091), UINT64_C(16807427164405733357), UINT64_C(7942358959831785217), UINT64_C(0)}, + u256{UINT64_C(15930919), UINT64_C(2053574980671369030), UINT64_C(5636613303479645706), UINT64_C(0)}, + u256{UINT64_C(159309191), UINT64_C(2089005733004138687), UINT64_C(1025900813667802212), UINT64_C(0)}, + u256{UINT64_C(1593091911), UINT64_C(2443313256331835254), UINT64_C(10259008136678022120), UINT64_C(0)}, + u256{UINT64_C(15930919111), UINT64_C(5986388489608800929), UINT64_C(10356360998232463120), UINT64_C(0)}, + u256{UINT64_C(159309191113), UINT64_C(4523652674959354447), UINT64_C(11329889613776873120), UINT64_C(0)}, + u256{UINT64_C(1593091911132), UINT64_C(8343038602174441244), UINT64_C(2618431695511421504), UINT64_C(0)}, + u256{UINT64_C(15930919111324), UINT64_C(9643409726906205977), UINT64_C(7737572881404663424), UINT64_C(0)}, + u256{UINT64_C(159309191113245), UINT64_C(4200376900514301694), UINT64_C(3588752519208427776), UINT64_C(0)}, + u256{UINT64_C(1593091911132452), UINT64_C(5110280857723913709), UINT64_C(17440781118374726144), UINT64_C(0)}, + u256{UINT64_C(15930919111324522), UINT64_C(14209320429820033867), UINT64_C(8387114520361296896), UINT64_C(0)}, + u256{UINT64_C(159309191113245227), UINT64_C(12965995782233477362), UINT64_C(10084168908774762496), UINT64_C(0)}, + u256{UINT64_C(1593091911132452277), UINT64_C(532749306367912313), UINT64_C(8607968719199866880), UINT64_C(0)}, + u256{UINT64_C(15930919111324522770), UINT64_C(5327493063679123134), UINT64_C(12292710897160462336), UINT64_C(0)}, + u256{UINT64_C(11735238523568814774), UINT64_C(16381442489372128114), UINT64_C(12246644529347313664), UINT64_C(0)}, }; } // namespace impl @@ -235,7 +237,7 @@ constexpr auto pow10(detail::builtin_uint128_t n) noexcept -> detail::builtin_ui constexpr auto pow10(const u256& n) noexcept -> u256 { - return impl::u256_pow_10[n[3]]; + return impl::u256_pow_10[static_cast(n)]; } #if defined(__GNUC__) && __GNUC__ >= 7 diff --git a/include/boost/decimal/detail/u256.hpp b/include/boost/decimal/detail/u256.hpp index f65ac96bb..dc4de1a77 100644 --- a/include/boost/decimal/detail/u256.hpp +++ b/include/boost/decimal/detail/u256.hpp @@ -33,7 +33,8 @@ u256 constexpr u256& operator=(u256&& other) noexcept = default; constexpr u256(std::uint64_t byte3, std::uint64_t byte2, std::uint64_t byte1, std::uint64_t byte0) noexcept; - constexpr u256(std::uint64_t x) { bytes[0] = x; } + constexpr u256(const int128::uint128_t x) noexcept { bytes[0] = x.low; bytes[1] = x.high; } + constexpr u256(const std::uint64_t x) noexcept { bytes[0] = x; } explicit constexpr operator std::uint64_t() const noexcept { return bytes[0]; } @@ -56,6 +57,8 @@ u256 constexpr u256& operator>>=(int amount) noexcept; constexpr u256& operator|=(const u256& rhs) noexcept; + constexpr u256& operator*=(const u256& rhs) noexcept; + constexpr u256& operator/=(const u256& rhs) noexcept; constexpr u256& operator/=(const int128::uint128_t& rhs) noexcept; constexpr u256& operator/=(std::uint64_t rhs) noexcept; @@ -365,6 +368,11 @@ constexpr bool operator>(const u256& lhs, const u256& rhs) noexcept return rhs < lhs; } +constexpr bool operator>(const u256& lhs, const int128::uint128_t& rhs) noexcept +{ + return lhs[3] > 0U || lhs[2] > 0U || int128::uint128_t{lhs[1], lhs[0]} > rhs; +} + //===================================== // Greater Equal Operator //===================================== @@ -910,6 +918,12 @@ constexpr u256 umul256(const int128::uint128_t& a, const int128::uint128_t& b) n return result; } +constexpr u256& u256::operator*=(const u256& rhs) noexcept +{ + *this = *this * rhs; + return *this; +} + //===================================== // Division Operators //===================================== diff --git a/test/github_issue_1260.cpp b/test/github_issue_1260.cpp index dc5af98f2..02552d59e 100644 --- a/test/github_issue_1260.cpp +++ b/test/github_issue_1260.cpp @@ -17,8 +17,50 @@ void test() const T add_val {lhs + rhs}; BOOST_TEST_EQ(add_val, res); - const T sub_val {lhs - boost::decimal::abs(rhs)}; - BOOST_TEST_EQ(sub_val, res); + //const T sub_val {lhs - boost::decimal::abs(rhs)}; + //BOOST_TEST_EQ(sub_val, res); +} + +template +void test2() +{ + const T lhs {"1E34"}; + const T rhs {"-0.501"}; + const T res {"9999999999999999999999999999999999"}; + + const T add_val {lhs + rhs}; + BOOST_TEST_EQ(add_val, res); + + //const T sub_val {lhs - boost::decimal::abs(rhs)}; + //BOOST_TEST_EQ(sub_val, res); +} + +template +void test3() +{ + const T lhs {"1E34"}; + const T rhs {"-0.5001"}; + const T res {"9999999999999999999999999999999999"}; + + const T add_val {lhs + rhs}; + BOOST_TEST_EQ(add_val, res); + + //const T sub_val {lhs - boost::decimal::abs(rhs)}; + //BOOST_TEST_EQ(sub_val, res); +} + +template +void test4() +{ + const T lhs {"1E34"}; + const T rhs {"-0.50001"}; + const T res {"9999999999999999999999999999999999"}; + + const T add_val {lhs + rhs}; + BOOST_TEST_EQ(add_val, res); + + //const T sub_val {lhs - boost::decimal::abs(rhs)}; + //BOOST_TEST_EQ(sub_val, res); } int main() @@ -29,6 +71,15 @@ int main() test(); test(); + test2(); + //test2(); + + test3(); + //test3(); + + test4(); + //test4(); + #endif return boost::report_errors(); diff --git a/test/test_big_uints.cpp b/test/test_big_uints.cpp index 7adac665f..966cd33d7 100644 --- a/test/test_big_uints.cpp +++ b/test/test_big_uints.cpp @@ -478,6 +478,7 @@ void test_digit_counting() int current_digits {1}; for (int i {}; i <= max_power; ++i) { + BOOST_TEST_EQ(current_power, boost::decimal::detail::pow10(static_cast(i))); BOOST_TEST_EQ(num_digits(current_power), current_digits); current_power = current_power * UINT64_C(10); ++current_digits;