From 0b59517ef88ddbef3315bb0f829ac89e799e70a6 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 21 Jun 2024 08:44:03 -0400 Subject: [PATCH 01/45] Remove repeated operations in decimal32 division --- include/boost/decimal/decimal32.hpp | 15 +++------------ include/boost/decimal/decimal32_fast.hpp | 10 ++-------- include/boost/decimal/detail/div_impl.hpp | 18 ++++-------------- 3 files changed, 9 insertions(+), 34 deletions(-) diff --git a/include/boost/decimal/decimal32.hpp b/include/boost/decimal/decimal32.hpp index 8e22ea15f..d49937357 100644 --- a/include/boost/decimal/decimal32.hpp +++ b/include/boost/decimal/decimal32.hpp @@ -1794,11 +1794,8 @@ constexpr auto div_impl(decimal32 lhs, decimal32 rhs, decimal32& q, decimal32& r detail::decimal32_components lhs_components {sig_lhs, exp_lhs, lhs.isneg()}; detail::decimal32_components rhs_components {sig_rhs, exp_rhs, rhs.isneg()}; - detail::decimal32_components q_components {}; - detail::generic_div_impl(lhs_components, rhs_components, q_components); - - q = decimal32(q_components.sig, q_components.exp, q_components.sign); + q = detail::generic_div_impl(lhs_components, rhs_components); } constexpr auto mod_impl(decimal32 lhs, decimal32 rhs, const decimal32& q, decimal32& r) noexcept -> void @@ -1858,11 +1855,8 @@ constexpr auto operator/(decimal32 lhs, Integer rhs) noexcept detail::decimal32_components lhs_components {sig_lhs, exp_lhs, lhs.isneg()}; std::int32_t exp_rhs {}; detail::decimal32_components rhs_components {detail::shrink_significand(detail::make_positive_unsigned(rhs), exp_rhs), exp_rhs, rhs < 0}; - detail::decimal32_components q_components {}; - - detail::generic_div_impl(lhs_components, rhs_components, q_components); - return decimal32(q_components.sig, q_components.exp, q_components.sign); + return detail::generic_div_impl(lhs_components, rhs_components); } template @@ -1903,11 +1897,8 @@ constexpr auto operator/(Integer lhs, decimal32 rhs) noexcept auto lhs_sig {detail::make_positive_unsigned(detail::shrink_significand(lhs, lhs_exp))}; detail::decimal32_components lhs_components {lhs_sig, lhs_exp, lhs < 0}; detail::decimal32_components rhs_components {sig_rhs, exp_rhs, rhs.isneg()}; - detail::decimal32_components q_components {}; - - detail::generic_div_impl(lhs_components, rhs_components, q_components); - return decimal32(q_components.sig, q_components.exp, q_components.sign); + return detail::generic_div_impl(lhs_components, rhs_components); } constexpr auto decimal32::operator/=(decimal32 rhs) noexcept -> decimal32& diff --git a/include/boost/decimal/decimal32_fast.hpp b/include/boost/decimal/decimal32_fast.hpp index 502e9dd5d..d19983d67 100644 --- a/include/boost/decimal/decimal32_fast.hpp +++ b/include/boost/decimal/decimal32_fast.hpp @@ -1117,11 +1117,8 @@ constexpr auto operator/(decimal32_fast lhs, Integer rhs) noexcept const detail::decimal32_fast_components lhs_components {lhs.significand_, lhs.biased_exponent(), lhs.sign_}; std::int32_t exp_rhs {}; const detail::decimal32_fast_components rhs_components {detail::shrink_significand(detail::make_positive_unsigned(rhs), exp_rhs), exp_rhs, rhs < 0}; - detail::decimal32_fast_components q_components {}; - detail::generic_div_impl(lhs_components, rhs_components, q_components); - - return {q_components.sig, q_components.exp, q_components.sign}; + return detail::generic_div_impl(lhs_components, rhs_components); } template @@ -1158,11 +1155,8 @@ constexpr auto operator/(Integer lhs, decimal32_fast rhs) noexcept const auto lhs_sig {detail::make_positive_unsigned(detail::shrink_significand(lhs, lhs_exp))}; const detail::decimal32_fast_components lhs_components {lhs_sig, lhs_exp, lhs < 0}; const detail::decimal32_fast_components rhs_components {rhs.significand_, rhs.biased_exponent(), rhs.isneg()}; - detail::decimal32_fast_components q_components {}; - - detail::generic_div_impl(lhs_components, rhs_components, q_components); - return {q_components.sig, q_components.exp, q_components.sign}; + return detail::generic_div_impl(lhs_components, rhs_components); } constexpr auto operator%(decimal32_fast lhs, decimal32_fast rhs) noexcept -> decimal32_fast diff --git a/include/boost/decimal/detail/div_impl.hpp b/include/boost/decimal/detail/div_impl.hpp index a9062116d..dda4a058e 100644 --- a/include/boost/decimal/detail/div_impl.hpp +++ b/include/boost/decimal/detail/div_impl.hpp @@ -16,8 +16,8 @@ namespace boost { namespace decimal { namespace detail { -template -BOOST_DECIMAL_FORCE_INLINE constexpr auto generic_div_impl(const T& lhs, const T& rhs, T& q) noexcept -> void +template +BOOST_DECIMAL_FORCE_INLINE constexpr auto generic_div_impl(const T& lhs, const T& rhs) noexcept -> DecimalType { bool sign {lhs.sign != rhs.sign}; @@ -28,28 +28,18 @@ BOOST_DECIMAL_FORCE_INLINE constexpr auto generic_div_impl(const T& lhs, const T auto res_sig {big_sig_lhs / static_cast(rhs.sig)}; auto res_exp {(lhs.exp - detail::precision) - rhs.exp}; - const auto sig_dig {detail::num_digits(res_sig)}; - - if (sig_dig > std::numeric_limits::digits10) - { - res_sig /= detail::pow10(static_cast(sig_dig - std::numeric_limits::digits10)); - res_exp += sig_dig - std::numeric_limits::digits10; - } - - const auto res_sig_32 {static_cast(res_sig)}; - #ifdef BOOST_DECIMAL_DEBUG std::cerr << "\nres sig: " << res_sig_32 << "\nres exp: " << res_exp << std::endl; #endif - if (res_sig_32 == 0) + if (res_sig == 0) { sign = false; } // Let the constructor handle shrinking it back down and rounding correctly - q = T{res_sig_32, res_exp, sign}; + return DecimalType{res_sig, res_exp, sign}; } template From 32137ce746ec796e934b77963e51cd48dd61e293 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 21 Jun 2024 08:50:37 -0400 Subject: [PATCH 02/45] Remove repeated operations in decimal64 division --- include/boost/decimal/decimal64.hpp | 15 +++------------ include/boost/decimal/decimal64_fast.hpp | 10 ++-------- include/boost/decimal/detail/div_impl.hpp | 18 ++++-------------- 3 files changed, 9 insertions(+), 34 deletions(-) diff --git a/include/boost/decimal/decimal64.hpp b/include/boost/decimal/decimal64.hpp index da2ce21bd..ddd6cb169 100644 --- a/include/boost/decimal/decimal64.hpp +++ b/include/boost/decimal/decimal64.hpp @@ -1165,11 +1165,8 @@ constexpr auto d64_div_impl(decimal64 lhs, decimal64 rhs, decimal64& q, decimal6 detail::decimal64_components lhs_components {sig_lhs, exp_lhs, lhs.isneg()}; detail::decimal64_components rhs_components {sig_rhs, exp_rhs, rhs.isneg()}; - detail::decimal64_components q_components {}; - detail::d64_generic_div_impl(lhs_components, rhs_components, q_components); - - q = decimal64(q_components.sig, q_components.exp, q_components.sign); + q = detail::d64_generic_div_impl(lhs_components, rhs_components); } constexpr auto d64_mod_impl(decimal64 lhs, decimal64 rhs, const decimal64& q, decimal64& r) noexcept -> void @@ -1509,11 +1506,8 @@ constexpr auto operator/(decimal64 lhs, Integer rhs) noexcept auto rhs_sig {static_cast(detail::make_positive_unsigned(rhs))}; std::int32_t rhs_exp {}; detail::decimal64_components rhs_components {detail::shrink_significand(rhs_sig, rhs_exp), rhs_exp, rhs < 0}; - detail::decimal64_components q_components {}; - - detail::d64_generic_div_impl(lhs_components, rhs_components, q_components); - return decimal64(q_components.sig, q_components.exp, q_components.sign); + return detail::d64_generic_div_impl(lhs_components, rhs_components); } template @@ -1552,11 +1546,8 @@ constexpr auto operator/(Integer lhs, decimal64 rhs) noexcept detail::decimal64_components lhs_components {detail::make_positive_unsigned(lhs), 0, lhs < 0}; detail::decimal64_components rhs_components {rhs_sig, rhs_exp, rhs.isneg()}; - detail::decimal64_components q_components {}; - - detail::d64_generic_div_impl(lhs_components, rhs_components, q_components); - return decimal64(q_components.sig, q_components.exp, q_components.sign); + return detail::d64_generic_div_impl(lhs_components, rhs_components); } constexpr auto operator%(decimal64 lhs, decimal64 rhs) noexcept -> decimal64 diff --git a/include/boost/decimal/decimal64_fast.hpp b/include/boost/decimal/decimal64_fast.hpp index 0744c66d7..835137166 100644 --- a/include/boost/decimal/decimal64_fast.hpp +++ b/include/boost/decimal/decimal64_fast.hpp @@ -1278,11 +1278,8 @@ constexpr auto operator/(decimal64_fast lhs, Integer rhs) noexcept auto rhs_sig {static_cast(detail::make_positive_unsigned(rhs))}; std::int32_t rhs_exp {}; detail::decimal64_fast_components rhs_components {detail::shrink_significand(rhs_sig, rhs_exp), rhs_exp, rhs < 0}; - detail::decimal64_fast_components q_components {}; - detail::d64_generic_div_impl(lhs_components, rhs_components, q_components); - - return {q_components.sig, q_components.exp, q_components.sign}; + return detail::d64_generic_div_impl(lhs_components, rhs_components); } template @@ -1321,11 +1318,8 @@ constexpr auto operator/(Integer lhs, decimal64_fast rhs) noexcept detail::decimal64_fast_components lhs_components {detail::make_positive_unsigned(lhs), 0, lhs < 0}; detail::decimal64_fast_components rhs_components {rhs_sig, rhs_exp, rhs.isneg()}; - detail::decimal64_fast_components q_components {}; - - detail::d64_generic_div_impl(lhs_components, rhs_components, q_components); - return {q_components.sig, q_components.exp, q_components.sign}; + return detail::d64_generic_div_impl(lhs_components, rhs_components); } constexpr auto operator%(decimal64_fast lhs, decimal64_fast rhs) noexcept -> decimal64_fast diff --git a/include/boost/decimal/detail/div_impl.hpp b/include/boost/decimal/detail/div_impl.hpp index dda4a058e..46fa73099 100644 --- a/include/boost/decimal/detail/div_impl.hpp +++ b/include/boost/decimal/detail/div_impl.hpp @@ -42,8 +42,8 @@ BOOST_DECIMAL_FORCE_INLINE constexpr auto generic_div_impl(const T& lhs, const T return DecimalType{res_sig, res_exp, sign}; } -template -constexpr auto d64_generic_div_impl(const T& lhs, const T& rhs, T& q) noexcept -> void +template +constexpr auto d64_generic_div_impl(const T& lhs, const T& rhs) noexcept -> DecimalType { #ifdef BOOST_DECIMAL_HAS_INT128 using unsigned_int128_type = boost::decimal::detail::uint128_t; @@ -61,23 +61,13 @@ constexpr auto d64_generic_div_impl(const T& lhs, const T& rhs, T& q) noexcept - auto res_sig {big_sig_lhs / static_cast(rhs.sig)}; auto res_exp {(lhs.exp - detail::precision_v) - rhs.exp}; - const auto sig_dig {detail::num_digits(res_sig)}; - - if (sig_dig > std::numeric_limits::digits10) - { - res_sig /= static_cast(detail::pow10(static_cast(sig_dig - std::numeric_limits::digits10))); - res_exp += sig_dig - std::numeric_limits::digits10; - } - - const auto res_sig_64 {static_cast(res_sig)}; - - if (res_sig_64 == 0) + if (res_sig == 0) { sign = false; } // Let the constructor handle shrinking it back down and rounding correctly - q = T{res_sig_64, res_exp, sign}; + return DecimalType{res_sig, res_exp, sign}; } template From 7ef20105f1a3de168f42bd19e1ab1353f5ecfacc Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 21 Jun 2024 10:56:51 -0400 Subject: [PATCH 03/45] Simplify 32 bit addition --- include/boost/decimal/decimal32.hpp | 18 +++++++----------- include/boost/decimal/decimal32_fast.hpp | 16 ++++++---------- include/boost/decimal/detail/add_impl.hpp | 3 +-- 3 files changed, 14 insertions(+), 23 deletions(-) diff --git a/include/boost/decimal/decimal32.hpp b/include/boost/decimal/decimal32.hpp index d49937357..7efd84dde 100644 --- a/include/boost/decimal/decimal32.hpp +++ b/include/boost/decimal/decimal32.hpp @@ -863,9 +863,8 @@ constexpr auto operator+(decimal32 lhs, decimal32 rhs) noexcept -> decimal32 auto exp_rhs {rhs.biased_exponent()}; detail::normalize(sig_rhs, exp_rhs); - const auto result {detail::add_impl(sig_lhs, exp_lhs, lhs.isneg(), sig_rhs, exp_rhs, rhs.isneg())}; - - return {result.sig, result.exp, result.sign}; + return {detail::add_impl(sig_lhs, exp_lhs, lhs.isneg(), + sig_rhs, exp_rhs, rhs.isneg())}; } template @@ -894,31 +893,28 @@ constexpr auto operator+(decimal32 lhs, Integer rhs) noexcept auto sig_rhs {rhs}; std::int32_t exp_rhs {0}; detail::normalize(sig_rhs, exp_rhs); - auto unsigned_sig_rhs = detail::shrink_significand(detail::make_positive_unsigned(sig_rhs), exp_rhs); + auto unsigned_sig_rhs = static_cast(detail::make_positive_unsigned(sig_rhs)); auto rhs_components {detail::decimal32_components{unsigned_sig_rhs, exp_rhs, (rhs < 0)}}; if (!lhs_bigger) { detail::swap(lhs_components, rhs_components); - lhs_bigger = !lhs_bigger; abs_lhs_bigger = !abs_lhs_bigger; } - detail::decimal32_components result {}; - if (!lhs_components.sign && rhs_components.sign) { + detail::decimal32_components result {}; result = detail::sub_impl(lhs_components.sig, lhs_components.exp, lhs_components.sign, rhs_components.sig, rhs_components.exp, rhs_components.sign, abs_lhs_bigger); + return decimal32(result.sig, result.exp, result.sign); } else { - result = detail::add_impl(lhs_components.sig, lhs_components.exp, lhs_components.sign, - rhs_components.sig, rhs_components.exp, rhs_components.sign); + return detail::add_impl(lhs_components.sig, lhs_components.exp, lhs_components.sign, + rhs_components.sig, rhs_components.exp, rhs_components.sign); } - - return decimal32(result.sig, result.exp, result.sign); } template diff --git a/include/boost/decimal/decimal32_fast.hpp b/include/boost/decimal/decimal32_fast.hpp index d19983d67..19dc18562 100644 --- a/include/boost/decimal/decimal32_fast.hpp +++ b/include/boost/decimal/decimal32_fast.hpp @@ -783,12 +783,10 @@ constexpr auto operator+(decimal32_fast lhs, decimal32_fast rhs) noexcept -> dec return lhs - abs(rhs); } - const auto result {detail::add_impl( + return {detail::add_impl( lhs.significand_, lhs.biased_exponent(), lhs.sign_, rhs.significand_, rhs.biased_exponent(), rhs.sign_ )}; - - return {result.sig, result.exp, result.sign}; } template @@ -814,7 +812,7 @@ constexpr auto operator+(decimal32_fast lhs, Integer rhs) noexcept auto sig_rhs {rhs}; std::int32_t exp_rhs {0}; detail::normalize(sig_rhs, exp_rhs); - auto unsigned_sig_rhs = detail::shrink_significand(detail::make_positive_unsigned(sig_rhs), exp_rhs); + auto unsigned_sig_rhs {static_cast(detail::make_positive_unsigned(sig_rhs))}; auto rhs_components {detail::decimal32_fast_components{unsigned_sig_rhs, exp_rhs, (rhs < 0)}}; if (!lhs_bigger) @@ -823,21 +821,19 @@ constexpr auto operator+(decimal32_fast lhs, Integer rhs) noexcept abs_lhs_bigger = !abs_lhs_bigger; } - detail::decimal32_fast_components result {}; - if (!lhs_components.sign && rhs_components.sign) { + detail::decimal32_fast_components result {}; result = detail::sub_impl(lhs_components.sig, lhs_components.exp, lhs_components.sign, rhs_components.sig, rhs_components.exp, rhs_components.sign, abs_lhs_bigger); + return {result.sig, result.exp, result.sign}; } else { - result = detail::add_impl(lhs_components.sig, lhs_components.exp, lhs_components.sign, - rhs_components.sig, rhs_components.exp, rhs_components.sign); + return detail::add_impl(lhs_components.sig, lhs_components.exp, lhs_components.sign, + rhs_components.sig, rhs_components.exp, rhs_components.sign); } - - return {result.sig, result.exp, result.sign}; } template diff --git a/include/boost/decimal/detail/add_impl.hpp b/include/boost/decimal/detail/add_impl.hpp index 72afb8b4f..de47f3990 100644 --- a/include/boost/decimal/detail/add_impl.hpp +++ b/include/boost/decimal/detail/add_impl.hpp @@ -80,7 +80,6 @@ BOOST_DECIMAL_FORCE_INLINE constexpr auto add_impl(T1 lhs_sig, std::int32_t lhs_ // Both of the significands are maximally 24 bits, so they fit into a 32-bit signed type just fine const auto new_sig {static_cast(lhs_sig + rhs_sig)}; const auto new_exp {lhs_exp}; - const auto res_sig {detail::make_positive_unsigned(new_sig)}; #ifdef BOOST_DECIMAL_DEBUG_ADD std::cerr << "Final sig lhs: " << lhs_sig @@ -88,7 +87,7 @@ BOOST_DECIMAL_FORCE_INLINE constexpr auto add_impl(T1 lhs_sig, std::int32_t lhs_ << "\nResult sig: " << new_sig << std::endl; #endif - return {res_sig, new_exp, sign}; + return {new_sig, new_exp, sign}; } template From 0dd9002ea13b0193d1454f550d8964f5bc0101fd Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 21 Jun 2024 11:20:01 -0400 Subject: [PATCH 04/45] Simplify 64 bit addition --- include/boost/decimal/decimal64.hpp | 23 +++++++++-------------- include/boost/decimal/decimal64_fast.hpp | 20 ++++++++------------ include/boost/decimal/detail/add_impl.hpp | 5 +++-- 3 files changed, 20 insertions(+), 28 deletions(-) diff --git a/include/boost/decimal/decimal64.hpp b/include/boost/decimal/decimal64.hpp index ddd6cb169..e9f793616 100644 --- a/include/boost/decimal/decimal64.hpp +++ b/include/boost/decimal/decimal64.hpp @@ -122,7 +122,7 @@ BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint64_t d64_construct_significand_mask = struct decimal64_components { - using sig_type = std::uint64_t; + using significand_type = std::uint64_t; std::uint64_t sig; std::int32_t exp; @@ -1215,10 +1215,8 @@ constexpr auto operator+(decimal64 lhs, decimal64 rhs) noexcept -> decimal64 auto rhs_exp {rhs.biased_exponent()}; detail::normalize(rhs_sig, rhs_exp); - const auto result {detail::d64_add_impl(lhs_sig, lhs_exp, lhs.isneg(), - rhs_sig, rhs_exp, rhs.isneg())}; - - return {result.sig, result.exp, result.sign}; + return {detail::d64_add_impl(lhs_sig, lhs_exp, lhs.isneg(), + rhs_sig, rhs_exp, rhs.isneg())}; } template @@ -1244,21 +1242,18 @@ constexpr auto operator+(decimal64 lhs, Integer rhs) noexcept detail::normalize(sig_lhs, exp_lhs); auto lhs_components {detail::decimal64_components{sig_lhs, exp_lhs, lhs.isneg()}}; - auto sig_rhs {static_cast(detail::make_positive_unsigned(rhs))}; + auto sig_rhs {static_cast(detail::make_positive_unsigned(rhs))}; std::int32_t exp_rhs {0}; detail::normalize(sig_rhs, exp_rhs); - auto unsigned_sig_rhs = detail::shrink_significand(detail::make_positive_unsigned(sig_rhs), exp_rhs); + auto unsigned_sig_rhs {static_cast(detail::make_positive_unsigned(sig_rhs))}; auto rhs_components {detail::decimal64_components{unsigned_sig_rhs, exp_rhs, (rhs < 0)}}; if (!lhs_bigger) { detail::swap(lhs_components, rhs_components); - lhs_bigger = !lhs_bigger; abs_lhs_bigger = !abs_lhs_bigger; } - detail::decimal64_components result {}; - #ifdef BOOST_DECIMAL_DEBUG_ADD std::cerr << "Lhs sig: " << lhs_components.sig << "\nLhs exp: " << lhs_components.exp @@ -1268,17 +1263,17 @@ constexpr auto operator+(decimal64 lhs, Integer rhs) noexcept if (!lhs_components.sign && rhs_components.sign) { + detail::decimal64_components result {}; result = detail::d64_sub_impl(lhs_components.sig, lhs_components.exp, lhs_components.sign, rhs_components.sig, rhs_components.exp, rhs_components.sign, abs_lhs_bigger); + return decimal64(result.sig, result.exp, result.sign); } else { - result = detail::d64_add_impl(lhs_components.sig, lhs_components.exp, lhs_components.sign, - rhs_components.sig, rhs_components.exp, rhs_components.sign); + return detail::d64_add_impl(lhs_components.sig, lhs_components.exp, lhs_components.sign, + rhs_components.sig, rhs_components.exp, rhs_components.sign); } - - return decimal64(result.sig, result.exp, result.sign); } template diff --git a/include/boost/decimal/decimal64_fast.hpp b/include/boost/decimal/decimal64_fast.hpp index 835137166..026817150 100644 --- a/include/boost/decimal/decimal64_fast.hpp +++ b/include/boost/decimal/decimal64_fast.hpp @@ -30,7 +30,7 @@ BOOST_DECIMAL_CONSTEXPR_VARIABLE auto d64_fast_snan = std::numeric_limits dec return lhs - abs(rhs); } - const auto result {detail::d64_add_impl( + return {detail::d64_add_impl( lhs.significand_, lhs.biased_exponent(), lhs.sign_, rhs.significand_, rhs.biased_exponent(), rhs.sign_ )}; - - return {result.sig, result.exp, result.sign}; } template @@ -931,10 +929,10 @@ constexpr auto operator+(decimal64_fast lhs, Integer rhs) noexcept auto lhs_components {detail::decimal64_fast_components{lhs.significand_, lhs.biased_exponent(), lhs.isneg()}}; - auto sig_rhs {static_cast(detail::make_positive_unsigned(rhs))}; + auto sig_rhs {static_cast(detail::make_positive_unsigned(rhs))}; std::int32_t exp_rhs {0}; detail::normalize(sig_rhs, exp_rhs); - auto unsigned_sig_rhs = detail::shrink_significand(detail::make_positive_unsigned(sig_rhs), exp_rhs); + auto unsigned_sig_rhs {static_cast(detail::make_positive_unsigned(sig_rhs))}; auto rhs_components {detail::decimal64_fast_components{unsigned_sig_rhs, exp_rhs, (rhs < 0)}}; if (!lhs_bigger) @@ -943,8 +941,6 @@ constexpr auto operator+(decimal64_fast lhs, Integer rhs) noexcept abs_lhs_bigger = !abs_lhs_bigger; } - detail::decimal64_fast_components result {}; - #ifdef BOOST_DECIMAL_DEBUG_ADD std::cerr << "Lhs sig: " << lhs_components.sig << "\nLhs exp: " << lhs_components.exp @@ -954,17 +950,17 @@ constexpr auto operator+(decimal64_fast lhs, Integer rhs) noexcept if (!lhs_components.sign && rhs_components.sign) { + detail::decimal64_fast_components result {}; result = detail::d64_sub_impl(lhs_components.sig, lhs_components.exp, lhs_components.sign, rhs_components.sig, rhs_components.exp, rhs_components.sign, abs_lhs_bigger); + return {result.sig, result.exp, result.sign}; } else { - result = detail::d64_add_impl(lhs_components.sig, lhs_components.exp, lhs_components.sign, - rhs_components.sig, rhs_components.exp, rhs_components.sign); + return detail::d64_add_impl(lhs_components.sig, lhs_components.exp, lhs_components.sign, + rhs_components.sig, rhs_components.exp, rhs_components.sign); } - - return {result.sig, result.exp, result.sign}; } template diff --git a/include/boost/decimal/detail/add_impl.hpp b/include/boost/decimal/detail/add_impl.hpp index de47f3990..9940ae8ce 100644 --- a/include/boost/decimal/detail/add_impl.hpp +++ b/include/boost/decimal/detail/add_impl.hpp @@ -78,7 +78,7 @@ BOOST_DECIMAL_FORCE_INLINE constexpr auto add_impl(T1 lhs_sig, std::int32_t lhs_ // Cast the results to signed types so that we can apply a sign at the end if necessary // Both of the significands are maximally 24 bits, so they fit into a 32-bit signed type just fine - const auto new_sig {static_cast(lhs_sig + rhs_sig)}; + const auto new_sig {static_cast(lhs_sig + rhs_sig)}; const auto new_exp {lhs_exp}; #ifdef BOOST_DECIMAL_DEBUG_ADD @@ -154,7 +154,8 @@ constexpr auto d64_add_impl(T1 lhs_sig, std::int32_t lhs_exp, bool lhs_sign, } // Both of the significands are well under 64-bits, so we can fit them into int64_t without issue - const auto new_sig {static_cast(lhs_sig) + static_cast(rhs_sig)}; + const auto new_sig {static_cast(lhs_sig) + + static_cast(rhs_sig)}; const auto new_exp {lhs_exp}; #ifdef BOOST_DECIMAL_DEBUG_ADD From da78a23f928789d9fd44fd768983ed219b36cad1 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 21 Jun 2024 13:32:31 -0400 Subject: [PATCH 05/45] Slightly simplify 32 bit subtraction implementation --- include/boost/decimal/decimal32.hpp | 4 +-- include/boost/decimal/decimal32_fast.hpp | 4 +-- include/boost/decimal/detail/mul_impl.hpp | 2 +- include/boost/decimal/detail/sub_impl.hpp | 33 ++++++++++++----------- 4 files changed, 23 insertions(+), 20 deletions(-) diff --git a/include/boost/decimal/decimal32.hpp b/include/boost/decimal/decimal32.hpp index 7efd84dde..db2867104 100644 --- a/include/boost/decimal/decimal32.hpp +++ b/include/boost/decimal/decimal32.hpp @@ -121,7 +121,7 @@ BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t d32_big_combination_field_mask = struct decimal32_components { - using sig_type = std::uint32_t; + using significand_type = std::uint32_t; std::uint32_t sig; std::int32_t exp; @@ -893,7 +893,7 @@ constexpr auto operator+(decimal32 lhs, Integer rhs) noexcept auto sig_rhs {rhs}; std::int32_t exp_rhs {0}; detail::normalize(sig_rhs, exp_rhs); - auto unsigned_sig_rhs = static_cast(detail::make_positive_unsigned(sig_rhs)); + auto unsigned_sig_rhs = static_cast(detail::make_positive_unsigned(sig_rhs)); auto rhs_components {detail::decimal32_components{unsigned_sig_rhs, exp_rhs, (rhs < 0)}}; if (!lhs_bigger) diff --git a/include/boost/decimal/decimal32_fast.hpp b/include/boost/decimal/decimal32_fast.hpp index 19dc18562..91a0cd069 100644 --- a/include/boost/decimal/decimal32_fast.hpp +++ b/include/boost/decimal/decimal32_fast.hpp @@ -29,7 +29,7 @@ BOOST_DECIMAL_CONSTEXPR_VARIABLE auto d32_fast_snan = std::numeric_limits(detail::make_positive_unsigned(sig_rhs))}; + auto unsigned_sig_rhs {static_cast(detail::make_positive_unsigned(sig_rhs))}; auto rhs_components {detail::decimal32_fast_components{unsigned_sig_rhs, exp_rhs, (rhs < 0)}}; if (!lhs_bigger) diff --git a/include/boost/decimal/detail/mul_impl.hpp b/include/boost/decimal/detail/mul_impl.hpp index f07c7fd10..1a03a051a 100644 --- a/include/boost/decimal/detail/mul_impl.hpp +++ b/include/boost/decimal/detail/mul_impl.hpp @@ -48,7 +48,7 @@ BOOST_DECIMAL_FORCE_INLINE constexpr auto mul_impl(T1 lhs_sig, std::int32_t lhs_ res_sig /= detail::pow10(static_cast(sig_dig - max_dig)); res_exp += sig_dig - max_dig; - const auto res_sig_32 {static_cast(res_sig)}; + const auto res_sig_32 {static_cast(res_sig)}; #ifdef BOOST_DECIMAL_DEBUG std::cerr << "\nres sig: " << res_sig_32 diff --git a/include/boost/decimal/detail/sub_impl.hpp b/include/boost/decimal/detail/sub_impl.hpp index 6b2dd87dd..6235a9b5f 100644 --- a/include/boost/decimal/detail/sub_impl.hpp +++ b/include/boost/decimal/detail/sub_impl.hpp @@ -49,22 +49,25 @@ BOOST_DECIMAL_FORCE_INLINE constexpr auto sub_impl(T1 lhs_sig, std::int32_t lhs_ --delta_exp; --exp_bigger; } - else if (delta_exp >= 2) - { - sig_bigger *= 100; - delta_exp -= 2; - exp_bigger -= 2; - } - - if (delta_exp > 1) - { - sig_smaller /= pow10(delta_exp - 1); - delta_exp = 1; - } - - if (delta_exp == 1) + else { - detail::fenv_round(sig_smaller, smaller_sign); + if (delta_exp >= 2) + { + sig_bigger *= 100; + delta_exp -= 2; + exp_bigger -= 2; + } + + if (delta_exp > 1) + { + sig_smaller /= pow10(delta_exp - 1); + delta_exp = 1; + } + + if (delta_exp == 1) + { + detail::fenv_round(sig_smaller, smaller_sign); + } } // Both of the significands are less than 9'999'999, so we can safely From 6ca21c686f1ff5384bc5984c7df5788dccda0203 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 21 Jun 2024 13:39:39 -0400 Subject: [PATCH 06/45] Fix potential overflow in decimal32 mixed type addition --- include/boost/decimal/decimal32.hpp | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/include/boost/decimal/decimal32.hpp b/include/boost/decimal/decimal32.hpp index db2867104..3f1b1cc3b 100644 --- a/include/boost/decimal/decimal32.hpp +++ b/include/boost/decimal/decimal32.hpp @@ -142,6 +142,7 @@ BOOST_DECIMAL_EXPORT class decimal32 final // NOLINT(cppcoreguidelines-special-m { public: using significand_type = std::uint32_t; + using biased_exponent_type = std::int32_t; private: @@ -151,7 +152,7 @@ BOOST_DECIMAL_EXPORT class decimal32 final // NOLINT(cppcoreguidelines-special-m constexpr auto unbiased_exponent() const noexcept -> std::uint32_t; // Returns the biased exponent - constexpr auto biased_exponent() const noexcept -> std::int32_t; + constexpr auto biased_exponent() const noexcept -> biased_exponent_type; // Returns the significand complete with the bits implied from the combination field constexpr auto full_significand() const noexcept -> std::uint32_t; @@ -871,6 +872,8 @@ template constexpr auto operator+(decimal32 lhs, Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32) { + using promoted_significand_type = std::conditional_t::digits10 < std::numeric_limits::digits10, decimal32::significand_type, detail::make_unsigned_t>; + #ifndef BOOST_DECIMAL_FAST_MATH if (isnan(lhs) || isinf(lhs)) { @@ -883,17 +886,21 @@ constexpr auto operator+(decimal32 lhs, Integer rhs) noexcept { lhs_bigger = !lhs_bigger; } - bool abs_lhs_bigger {abs(lhs) > detail::make_positive_unsigned(rhs)}; + + // Make the significand type wide enough that it won't overflow during normalization + auto sig_rhs {static_cast(detail::make_positive_unsigned(rhs))}; + bool abs_lhs_bigger {abs(lhs) > sig_rhs}; auto sig_lhs {lhs.full_significand()}; auto exp_lhs {lhs.biased_exponent()}; detail::normalize(sig_lhs, exp_lhs); - auto lhs_components {detail::decimal32_components{sig_lhs, exp_lhs, lhs.isneg()}}; - auto sig_rhs {rhs}; - std::int32_t exp_rhs {0}; + + decimal32::biased_exponent_type exp_rhs {0}; detail::normalize(sig_rhs, exp_rhs); - auto unsigned_sig_rhs = static_cast(detail::make_positive_unsigned(sig_rhs)); + + // Now that the rhs has been normalized it is guaranteed to fit into the decimal32 significand type + auto unsigned_sig_rhs {static_cast(detail::make_positive_unsigned(sig_rhs))}; auto rhs_components {detail::decimal32_components{unsigned_sig_rhs, exp_rhs, (rhs < 0)}}; if (!lhs_bigger) @@ -1395,9 +1402,9 @@ constexpr auto decimal32::unbiased_exponent() const noexcept -> std::uint32_t return expval; } -constexpr auto decimal32::biased_exponent() const noexcept -> std::int32_t +constexpr auto decimal32::biased_exponent() const noexcept -> biased_exponent_type { - return static_cast(unbiased_exponent()) - detail::bias; + return static_cast(unbiased_exponent()) - detail::bias; } template From 84581d993bd8ba9ac7dded74aa177c6fe040eb53 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 21 Jun 2024 14:03:02 -0400 Subject: [PATCH 07/45] Add additional typedefs --- include/boost/decimal/decimal32.hpp | 18 ++++++++++-------- include/boost/decimal/decimal32_fast.hpp | 14 ++++++++------ include/boost/decimal/detail/sub_impl.hpp | 18 ++++++++++-------- 3 files changed, 28 insertions(+), 22 deletions(-) diff --git a/include/boost/decimal/decimal32.hpp b/include/boost/decimal/decimal32.hpp index 3f1b1cc3b..07fce0948 100644 --- a/include/boost/decimal/decimal32.hpp +++ b/include/boost/decimal/decimal32.hpp @@ -122,9 +122,10 @@ BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint32_t d32_big_combination_field_mask = struct decimal32_components { using significand_type = std::uint32_t; + using biased_exponent_type = std::int32_t; - std::uint32_t sig; - std::int32_t exp; + significand_type sig; + biased_exponent_type exp; bool sign; }; @@ -142,6 +143,7 @@ BOOST_DECIMAL_EXPORT class decimal32 final // NOLINT(cppcoreguidelines-special-m { public: using significand_type = std::uint32_t; + using exponent_type = std::uint32_t; using biased_exponent_type = std::int32_t; private: @@ -149,13 +151,13 @@ BOOST_DECIMAL_EXPORT class decimal32 final // NOLINT(cppcoreguidelines-special-m std::uint32_t bits_ {}; // Returns the un-biased (quantum) exponent - constexpr auto unbiased_exponent() const noexcept -> std::uint32_t; + constexpr auto unbiased_exponent() const noexcept -> exponent_type ; // Returns the biased exponent constexpr auto biased_exponent() const noexcept -> biased_exponent_type; // Returns the significand complete with the bits implied from the combination field - constexpr auto full_significand() const noexcept -> std::uint32_t; + constexpr auto full_significand() const noexcept -> significand_type ; constexpr auto isneg() const noexcept -> bool; // Attempts conversion to integral type: @@ -1377,9 +1379,9 @@ constexpr auto operator<=>(Integer lhs, decimal32 rhs) noexcept #endif -constexpr auto decimal32::unbiased_exponent() const noexcept -> std::uint32_t +constexpr auto decimal32::unbiased_exponent() const noexcept -> exponent_type { - std::uint32_t expval {}; + exponent_type expval {}; const auto exp_comb_bits {(bits_ & detail::d32_comb_11_mask)}; @@ -1414,9 +1416,9 @@ constexpr auto decimal32::edit_exponent(T expval) noexcept *this = decimal32(this->full_significand(), expval, this->isneg()); } -constexpr auto decimal32::full_significand() const noexcept -> std::uint32_t +constexpr auto decimal32::full_significand() const noexcept -> significand_type { - std::uint32_t significand {}; + significand_type significand {}; if ((bits_ & detail::d32_comb_11_mask) == detail::d32_comb_11_mask) { diff --git a/include/boost/decimal/decimal32_fast.hpp b/include/boost/decimal/decimal32_fast.hpp index 91a0cd069..358a1f383 100644 --- a/include/boost/decimal/decimal32_fast.hpp +++ b/include/boost/decimal/decimal32_fast.hpp @@ -30,9 +30,10 @@ BOOST_DECIMAL_CONSTEXPR_VARIABLE auto d32_fast_snan = std::numeric_limits bool @@ -68,9 +70,9 @@ class decimal32_fast final return exponent_; } - constexpr auto biased_exponent() const noexcept -> std::int32_t + constexpr auto biased_exponent() const noexcept -> biased_exponent_type { - return static_cast(exponent_) - detail::bias_v; + return static_cast(exponent_) - detail::bias_v; } friend constexpr auto div_impl(decimal32_fast lhs, decimal32_fast rhs, decimal32_fast& q, decimal32_fast& r) noexcept -> void; diff --git a/include/boost/decimal/detail/sub_impl.hpp b/include/boost/decimal/detail/sub_impl.hpp index 6235a9b5f..e56379ddd 100644 --- a/include/boost/decimal/detail/sub_impl.hpp +++ b/include/boost/decimal/detail/sub_impl.hpp @@ -17,11 +17,13 @@ namespace boost { namespace decimal { namespace detail { -template -BOOST_DECIMAL_FORCE_INLINE constexpr auto sub_impl(T1 lhs_sig, std::int32_t lhs_exp, bool lhs_sign, - T2 rhs_sig, std::int32_t rhs_exp, bool rhs_sign, +template +BOOST_DECIMAL_FORCE_INLINE constexpr auto sub_impl(T lhs_sig, U lhs_exp, bool lhs_sign, + T rhs_sig, U rhs_exp, bool rhs_sign, bool abs_lhs_bigger) noexcept -> ReturnType { + using sub_type = detail::make_signed_t; + auto delta_exp {lhs_exp > rhs_exp ? lhs_exp - rhs_exp : rhs_exp - lhs_exp}; auto signed_sig_lhs {detail::make_signed_value(lhs_sig, lhs_sign)}; auto signed_sig_rhs {detail::make_signed_value(rhs_sig, rhs_sign)}; @@ -32,8 +34,8 @@ BOOST_DECIMAL_FORCE_INLINE constexpr auto sub_impl(T1 lhs_sig, std::int32_t lhs_ // we return the larger of the two // // e.g. 1e20 - 1e-20 = 1e20 - return abs_lhs_bigger ? ReturnType{detail::shrink_significand(lhs_sig, lhs_exp), lhs_exp, false} : - ReturnType{detail::shrink_significand(rhs_sig, rhs_exp), rhs_exp, true}; + return abs_lhs_bigger ? ReturnType{lhs_sig, lhs_exp, false} : + ReturnType{rhs_sig, rhs_exp, true}; } // The two numbers can be subtracted together without special handling @@ -72,9 +74,9 @@ BOOST_DECIMAL_FORCE_INLINE constexpr auto sub_impl(T1 lhs_sig, std::int32_t lhs_ // Both of the significands are less than 9'999'999, so we can safely // cast them to signed 32-bit ints to calculate the new significand - std::int32_t new_sig = (rhs_sign && !lhs_sign) ? - static_cast(signed_sig_lhs) + static_cast(signed_sig_rhs) : - static_cast(signed_sig_lhs) - static_cast(signed_sig_rhs); + const auto new_sig = (rhs_sign && !lhs_sign) ? + static_cast(signed_sig_lhs) + static_cast(signed_sig_rhs) : + static_cast(signed_sig_lhs) - static_cast(signed_sig_rhs); const auto new_exp {abs_lhs_bigger ? lhs_exp : rhs_exp}; const auto new_sign {new_sig < 0}; From a6101b999627a250d3180c2f4a1f67bc7cb6dc9c Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 21 Jun 2024 14:22:05 -0400 Subject: [PATCH 08/45] Apply new sub impl to addition --- include/boost/decimal/decimal32.hpp | 8 +++----- include/boost/decimal/decimal32_fast.hpp | 8 +++----- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/include/boost/decimal/decimal32.hpp b/include/boost/decimal/decimal32.hpp index 07fce0948..c5701106c 100644 --- a/include/boost/decimal/decimal32.hpp +++ b/include/boost/decimal/decimal32.hpp @@ -913,11 +913,9 @@ constexpr auto operator+(decimal32 lhs, Integer rhs) noexcept if (!lhs_components.sign && rhs_components.sign) { - detail::decimal32_components result {}; - result = detail::sub_impl(lhs_components.sig, lhs_components.exp, lhs_components.sign, - rhs_components.sig, rhs_components.exp, rhs_components.sign, - abs_lhs_bigger); - return decimal32(result.sig, result.exp, result.sign); + return detail::sub_impl(lhs_components.sig, lhs_components.exp, lhs_components.sign, + rhs_components.sig, rhs_components.exp, rhs_components.sign, + abs_lhs_bigger); } else { diff --git a/include/boost/decimal/decimal32_fast.hpp b/include/boost/decimal/decimal32_fast.hpp index 358a1f383..2f45a8ea8 100644 --- a/include/boost/decimal/decimal32_fast.hpp +++ b/include/boost/decimal/decimal32_fast.hpp @@ -825,11 +825,9 @@ constexpr auto operator+(decimal32_fast lhs, Integer rhs) noexcept if (!lhs_components.sign && rhs_components.sign) { - detail::decimal32_fast_components result {}; - result = detail::sub_impl(lhs_components.sig, lhs_components.exp, lhs_components.sign, - rhs_components.sig, rhs_components.exp, rhs_components.sign, - abs_lhs_bigger); - return {result.sig, result.exp, result.sign}; + return detail::sub_impl(lhs_components.sig, lhs_components.exp, lhs_components.sign, + rhs_components.sig, rhs_components.exp, rhs_components.sign, + abs_lhs_bigger); } else { From 211a43d2a008ea0b939185a008091c6a4e25caca Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 21 Jun 2024 14:47:40 -0400 Subject: [PATCH 09/45] Simplify 32 bit subtraction --- include/boost/decimal/decimal32.hpp | 48 +++++++++++++---------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/include/boost/decimal/decimal32.hpp b/include/boost/decimal/decimal32.hpp index c5701106c..01b9531ad 100644 --- a/include/boost/decimal/decimal32.hpp +++ b/include/boost/decimal/decimal32.hpp @@ -993,17 +993,17 @@ constexpr auto operator-(decimal32 lhs, decimal32 rhs) noexcept -> decimal32 auto exp_rhs {rhs.biased_exponent()}; detail::normalize(sig_rhs, exp_rhs); - const auto result {detail::sub_impl(sig_lhs, exp_lhs, lhs.isneg(), - sig_rhs, exp_rhs, rhs.isneg(), - abs_lhs_bigger)}; - - return {result.sig, result.exp, result.sign}; + return {detail::sub_impl(sig_lhs, exp_lhs, lhs.isneg(), + sig_rhs, exp_rhs, rhs.isneg(), + abs_lhs_bigger)}; } template constexpr auto operator-(decimal32 lhs, Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32) { + using promoted_significand_type = std::conditional_t::digits10 < std::numeric_limits::digits10, decimal32::significand_type, detail::make_unsigned_t>; + #ifndef BOOST_DECIMAL_FAST_MATH if (isinf(lhs) || isnan(lhs)) { @@ -1016,30 +1016,28 @@ constexpr auto operator-(decimal32 lhs, Integer rhs) noexcept return lhs + detail::make_positive_unsigned(rhs); } - const bool abs_lhs_bigger {abs(lhs) > detail::make_positive_unsigned(rhs)}; + auto sig_rhs {static_cast(detail::make_positive_unsigned(rhs))}; + const bool abs_lhs_bigger {abs(lhs) > sig_rhs}; auto sig_lhs {lhs.full_significand()}; auto exp_lhs {lhs.biased_exponent()}; detail::normalize(sig_lhs, exp_lhs); - auto lhs_components {detail::decimal32_components{sig_lhs, exp_lhs, lhs.isneg()}}; - auto sig_rhs {rhs}; - std::int32_t exp_rhs {0}; + decimal32::biased_exponent_type exp_rhs {0}; detail::normalize(sig_rhs, exp_rhs); - auto unsigned_sig_rhs = detail::shrink_significand(detail::make_positive_unsigned(sig_rhs), exp_rhs); - auto rhs_components {detail::decimal32_components{unsigned_sig_rhs, exp_rhs, (rhs < 0)}}; + auto final_sig_rhs {static_cast(sig_rhs)}; - const auto result {detail::sub_impl(lhs_components.sig, lhs_components.exp, lhs_components.sign, - rhs_components.sig, rhs_components.exp, rhs_components.sign, - abs_lhs_bigger)}; - - return {result.sig, result.exp, result.sign}; + return {detail::sub_impl(sig_lhs, exp_lhs, lhs.isneg(), + final_sig_rhs, exp_rhs, (rhs < 0), + abs_lhs_bigger)}; } template constexpr auto operator-(Integer lhs, decimal32 rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32) { + using promoted_significand_type = std::conditional_t::digits10 < std::numeric_limits::digits10, decimal32::significand_type, detail::make_unsigned_t>; + #ifndef BOOST_DECIMAL_FAST_MATH if (isinf(rhs) || isnan(rhs)) { @@ -1052,24 +1050,20 @@ constexpr auto operator-(Integer lhs, decimal32 rhs) noexcept return lhs + (-rhs); } - const bool abs_lhs_bigger {detail::make_positive_unsigned(lhs) > abs(rhs)}; + auto sig_lhs {static_cast(detail::make_positive_unsigned(lhs))}; + const bool abs_lhs_bigger {sig_lhs > abs(rhs)}; - auto sig_lhs {detail::make_positive_unsigned(lhs)}; - std::int32_t exp_lhs {0}; + decimal32::biased_exponent_type exp_lhs {0}; detail::normalize(sig_lhs, exp_lhs); - auto unsigned_sig_lhs = detail::shrink_significand(detail::make_positive_unsigned(sig_lhs), exp_lhs); - auto lhs_components {detail::decimal32_components{unsigned_sig_lhs, exp_lhs, (lhs < 0)}}; + auto final_sig_lhs {static_cast(sig_lhs)}; auto sig_rhs {rhs.full_significand()}; auto exp_rhs {rhs.biased_exponent()}; detail::normalize(sig_rhs, exp_rhs); - auto rhs_components {detail::decimal32_components{sig_rhs, exp_rhs, rhs.isneg()}}; - const auto result {detail::sub_impl(lhs_components.sig, lhs_components.exp, lhs_components.sign, - rhs_components.sig, rhs_components.exp, rhs_components.sign, - abs_lhs_bigger)}; - - return {result.sig, result.exp, result.sign}; + return {detail::sub_impl(final_sig_lhs, exp_lhs, (lhs < 0), + sig_rhs, exp_rhs, rhs.isneg(), + abs_lhs_bigger)}; } constexpr auto decimal32::operator--() noexcept -> decimal32& From 1c1b44465569f37766e63d0aec9a345baa1b5e65 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 21 Jun 2024 15:05:48 -0400 Subject: [PATCH 10/45] Fix and simplify decimal32_fast subtraction --- include/boost/decimal/decimal32_fast.hpp | 60 +++++++++++------------- 1 file changed, 28 insertions(+), 32 deletions(-) diff --git a/include/boost/decimal/decimal32_fast.hpp b/include/boost/decimal/decimal32_fast.hpp index 2f45a8ea8..3b71be722 100644 --- a/include/boost/decimal/decimal32_fast.hpp +++ b/include/boost/decimal/decimal32_fast.hpp @@ -795,6 +795,8 @@ template constexpr auto operator+(decimal32_fast lhs, Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32_fast) { + using promoted_significand_type = std::conditional_t::digits10 < std::numeric_limits::digits10, decimal32::significand_type, detail::make_unsigned_t>; + #ifndef BOOST_DECIMAL_FAST_MATH if (isnan(lhs) || isinf(lhs)) { @@ -807,14 +809,15 @@ constexpr auto operator+(decimal32_fast lhs, Integer rhs) noexcept { lhs_bigger = !lhs_bigger; } - bool abs_lhs_bigger {abs(lhs) > detail::make_positive_unsigned(rhs)}; + + auto sig_rhs {static_cast(detail::make_positive_unsigned(rhs))}; + bool abs_lhs_bigger {abs(lhs) > sig_rhs}; auto lhs_components {detail::decimal32_fast_components{lhs.significand_, lhs.biased_exponent(), lhs.isneg()}}; - auto sig_rhs {rhs}; - std::int32_t exp_rhs {0}; + decimal32_fast::biased_exponent_type exp_rhs {0}; detail::normalize(sig_rhs, exp_rhs); - auto unsigned_sig_rhs {static_cast(detail::make_positive_unsigned(sig_rhs))}; + auto unsigned_sig_rhs {static_cast(detail::make_positive_unsigned(sig_rhs))}; auto rhs_components {detail::decimal32_fast_components{unsigned_sig_rhs, exp_rhs, (rhs < 0)}}; if (!lhs_bigger) @@ -862,19 +865,19 @@ constexpr auto operator-(decimal32_fast lhs, decimal32_fast rhs) noexcept -> dec const bool abs_lhs_bigger {abs(lhs) > abs(rhs)}; - const auto result {detail::sub_impl( + return {detail::sub_impl( lhs.significand_, lhs.biased_exponent(), lhs.sign_, rhs.significand_, rhs.biased_exponent(), rhs.sign_, abs_lhs_bigger )}; - - return {result.sig, result.exp, result.sign}; } template constexpr auto operator-(decimal32_fast lhs, Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32_fast) { + using promoted_significand_type = std::conditional_t::digits10 < std::numeric_limits::digits10, decimal32::significand_type, detail::make_unsigned_t>; + #ifndef BOOST_DECIMAL_FAST_MATH if (isinf(lhs) || isnan(lhs)) { @@ -882,33 +885,31 @@ constexpr auto operator-(decimal32_fast lhs, Integer rhs) noexcept } #endif + auto sig_rhs {static_cast(detail::make_positive_unsigned(rhs))}; + if (!lhs.isneg() && (rhs < 0)) { - return lhs + detail::make_positive_unsigned(rhs); + return lhs + sig_rhs; } - const bool abs_lhs_bigger {abs(lhs) > detail::make_positive_unsigned(rhs)}; - - auto lhs_components {detail::decimal32_fast_components{lhs.significand_, lhs.biased_exponent(), lhs.isneg()}}; + const bool abs_lhs_bigger {abs(lhs) > sig_rhs}; - auto sig_rhs {rhs}; - std::int32_t exp_rhs {0}; + decimal32_fast::biased_exponent_type exp_rhs {0}; detail::normalize(sig_rhs, exp_rhs); - auto unsigned_sig_rhs = detail::shrink_significand(detail::make_positive_unsigned(sig_rhs), exp_rhs); - auto rhs_components {detail::decimal32_fast_components{unsigned_sig_rhs, exp_rhs, (rhs < 0)}}; + auto final_sig_rhs {static_cast(detail::make_positive_unsigned(sig_rhs))}; - const auto result {detail::sub_impl( - lhs_components.sig, lhs_components.exp, lhs_components.sign, - rhs_components.sig, rhs_components.exp, rhs_components.sign, + return {detail::sub_impl( + lhs.significand_, lhs.biased_exponent(), lhs.sign_, + final_sig_rhs, exp_rhs, (rhs < 0), abs_lhs_bigger)}; - - return {result.sig, result.exp, result.sign}; } template constexpr auto operator-(Integer lhs, decimal32_fast rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32_fast) { + using promoted_significand_type = std::conditional_t::digits10 < std::numeric_limits::digits10, decimal32::significand_type, detail::make_unsigned_t>; + #ifndef BOOST_DECIMAL_FAST_MATH if (isinf(rhs) || isnan(rhs)) { @@ -921,23 +922,18 @@ constexpr auto operator-(Integer lhs, decimal32_fast rhs) noexcept return lhs + (-rhs); } - const bool abs_lhs_bigger {detail::make_positive_unsigned(lhs) > abs(rhs)}; + auto sig_lhs {static_cast(detail::make_positive_unsigned(lhs))}; + const bool abs_lhs_bigger {sig_lhs > abs(rhs)}; - auto sig_lhs {detail::make_positive_unsigned(lhs)}; - std::int32_t exp_lhs {0}; + decimal32_fast::biased_exponent_type exp_lhs {0}; detail::normalize(sig_lhs, exp_lhs); - auto unsigned_sig_lhs = detail::shrink_significand(detail::make_positive_unsigned(sig_lhs), exp_lhs); - auto lhs_components {detail::decimal32_fast_components{unsigned_sig_lhs, exp_lhs, (lhs < 0)}}; + auto final_sig_lhs {static_cast(detail::make_positive_unsigned(sig_lhs))}; - auto rhs_components {detail::decimal32_fast_components{rhs.significand_, rhs.biased_exponent(), rhs.isneg()}}; - - const auto result {detail::sub_impl( - lhs_components.sig, lhs_components.exp, lhs_components.sign, - rhs_components.sig, rhs_components.exp, rhs_components.sign, + return {detail::sub_impl( + final_sig_lhs, exp_lhs, (lhs < 0), + rhs.significand_, rhs.biased_exponent(), rhs.sign_, abs_lhs_bigger )}; - - return {result.sig, result.exp, result.sign}; } constexpr auto operator*(decimal32_fast lhs, decimal32_fast rhs) noexcept -> decimal32_fast From 643450df0a3a0c1600da4da7042862c117401fd2 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 21 Jun 2024 15:13:00 -0400 Subject: [PATCH 11/45] Add additional typedefs --- include/boost/decimal/decimal64.hpp | 23 +++++++++++++---------- include/boost/decimal/decimal64_fast.hpp | 9 +++++---- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/include/boost/decimal/decimal64.hpp b/include/boost/decimal/decimal64.hpp index e9f793616..7904afbaf 100644 --- a/include/boost/decimal/decimal64.hpp +++ b/include/boost/decimal/decimal64.hpp @@ -123,9 +123,10 @@ BOOST_DECIMAL_CONSTEXPR_VARIABLE std::uint64_t d64_construct_significand_mask = struct decimal64_components { using significand_type = std::uint64_t; + using biased_exponent_type = std::int32_t; - std::uint64_t sig; - std::int32_t exp; + significand_type sig; + biased_exponent_type exp; bool sign; }; @@ -140,16 +141,18 @@ BOOST_DECIMAL_EXPORT class decimal64 final { public: using significand_type = std::uint64_t; + using exponent_type = std::uint64_t; + using biased_exponent_type = std::int32_t; private: std::uint64_t bits_ {}; // Returns the un-biased (quantum) exponent - constexpr auto unbiased_exponent() const noexcept -> std::uint64_t; + constexpr auto unbiased_exponent() const noexcept -> exponent_type; // Returns the biased exponent - constexpr auto biased_exponent() const noexcept -> std::int32_t; + constexpr auto biased_exponent() const noexcept -> biased_exponent_type; // Allows direct editing of the exp template @@ -157,7 +160,7 @@ BOOST_DECIMAL_EXPORT class decimal64 final BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, T, void); // Returns the significand complete with the bits implied from the combination field - constexpr auto full_significand() const noexcept -> std::uint64_t; + constexpr auto full_significand() const noexcept -> significand_type; constexpr auto isneg() const noexcept -> bool; constexpr auto edit_sign(bool sign) noexcept -> void; @@ -976,9 +979,9 @@ constexpr decimal64::operator std::bfloat16_t() const noexcept } #endif -constexpr auto decimal64::unbiased_exponent() const noexcept -> std::uint64_t +constexpr auto decimal64::unbiased_exponent() const noexcept -> exponent_type { - std::uint64_t expval {}; + exponent_type expval {}; const auto exp_comb_bits {(bits_ & detail::d64_comb_11_mask)}; @@ -1000,14 +1003,14 @@ constexpr auto decimal64::unbiased_exponent() const noexcept -> std::uint64_t return expval; } -constexpr auto decimal64::biased_exponent() const noexcept -> std::int32_t +constexpr auto decimal64::biased_exponent() const noexcept -> biased_exponent_type { return static_cast(unbiased_exponent()) - detail::bias_v; } -constexpr auto decimal64::full_significand() const noexcept -> std::uint64_t +constexpr auto decimal64::full_significand() const noexcept -> significand_type { - std::uint64_t significand {}; + significand_type significand {}; if ((bits_ & detail::d64_comb_11_mask) == detail::d64_comb_11_mask) { diff --git a/include/boost/decimal/decimal64_fast.hpp b/include/boost/decimal/decimal64_fast.hpp index 026817150..ae95cedb4 100644 --- a/include/boost/decimal/decimal64_fast.hpp +++ b/include/boost/decimal/decimal64_fast.hpp @@ -31,9 +31,10 @@ BOOST_DECIMAL_CONSTEXPR_VARIABLE auto d64_fast_snan = std::numeric_limits bool From 848208811aebbe7ec2e65ccc6ed8d2bf0585527d Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 24 Jun 2024 08:32:26 -0400 Subject: [PATCH 12/45] Simplify 64 bit operator- --- include/boost/decimal/decimal64.hpp | 48 +++++++++++++---------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/include/boost/decimal/decimal64.hpp b/include/boost/decimal/decimal64.hpp index 7904afbaf..1525be2a7 100644 --- a/include/boost/decimal/decimal64.hpp +++ b/include/boost/decimal/decimal64.hpp @@ -1314,17 +1314,17 @@ constexpr auto operator-(decimal64 lhs, decimal64 rhs) noexcept -> decimal64 auto exp_rhs {rhs.biased_exponent()}; detail::normalize(sig_rhs, exp_rhs); - const auto result {detail::d64_sub_impl(sig_lhs, exp_lhs, lhs.isneg(), - sig_rhs, exp_rhs, rhs.isneg(), - abs_lhs_bigger)}; - - return {result.sig, result.exp, result.sign}; + return {detail::d64_sub_impl(sig_lhs, exp_lhs, lhs.isneg(), + sig_rhs, exp_rhs, rhs.isneg(), + abs_lhs_bigger)}; } template constexpr auto operator-(decimal64 lhs, Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal64) { + using promoted_significand_type = std::conditional_t::digits10 < std::numeric_limits::digits10, decimal64::significand_type, detail::make_unsigned_t>; + #ifndef BOOST_DECIMAL_FAST_MATH if (isinf(lhs) || isnan(lhs)) { @@ -1337,30 +1337,28 @@ constexpr auto operator-(decimal64 lhs, Integer rhs) noexcept return lhs + detail::make_positive_unsigned(rhs); } - const bool abs_lhs_bigger {abs(lhs) > detail::make_positive_unsigned(rhs)}; + auto sig_rhs {static_cast(detail::make_positive_unsigned(rhs))}; + const bool abs_lhs_bigger {abs(lhs) > sig_rhs}; auto sig_lhs {lhs.full_significand()}; auto exp_lhs {lhs.biased_exponent()}; detail::normalize(sig_lhs, exp_lhs); - auto lhs_components {detail::decimal64_components{sig_lhs, exp_lhs, lhs.isneg()}}; - auto sig_rhs {static_cast(detail::make_positive_unsigned(rhs))}; - std::int32_t exp_rhs {0}; + decimal64::biased_exponent_type exp_rhs {0}; detail::normalize(sig_rhs, exp_rhs); - auto unsigned_sig_rhs = detail::shrink_significand(detail::make_positive_unsigned(sig_rhs), exp_rhs); - auto rhs_components {detail::decimal64_components{unsigned_sig_rhs, exp_rhs, (rhs < 0)}}; + const auto final_sig_rhs {static_cast(sig_rhs)}; - const auto result {detail::d64_sub_impl(lhs_components.sig, lhs_components.exp, lhs_components.sign, - rhs_components.sig, rhs_components.exp, rhs_components.sign, - abs_lhs_bigger)}; - - return {result.sig, result.exp, result.sign}; + return {detail::d64_sub_impl(sig_lhs, exp_lhs, lhs.isneg(), + final_sig_rhs, exp_rhs, (rhs < 0), + abs_lhs_bigger)}; } template constexpr auto operator-(Integer lhs, decimal64 rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal64) { + using promoted_significand_type = std::conditional_t::digits10 < std::numeric_limits::digits10, decimal64::significand_type, detail::make_unsigned_t>; + #ifndef BOOST_DECIMAL_FAST_MATH if (isinf(rhs) || isnan(rhs)) { @@ -1373,24 +1371,20 @@ constexpr auto operator-(Integer lhs, decimal64 rhs) noexcept return lhs + (-rhs); } - const bool abs_lhs_bigger {detail::make_positive_unsigned(lhs) > abs(rhs)}; + auto sig_lhs {static_cast(detail::make_positive_unsigned(lhs))}; + const bool abs_lhs_bigger {sig_lhs > abs(rhs)}; - auto sig_lhs {static_cast(detail::make_positive_unsigned(lhs))}; - std::int32_t exp_lhs {0}; + decimal64::biased_exponent_type exp_lhs {0}; detail::normalize(sig_lhs, exp_lhs); - auto unsigned_sig_lhs = detail::shrink_significand(detail::make_positive_unsigned(sig_lhs), exp_lhs); - auto lhs_components {detail::decimal64_components{unsigned_sig_lhs, exp_lhs, (lhs < 0)}}; + const auto final_sig_lhs {static_cast(detail::make_positive_unsigned(sig_lhs))}; auto sig_rhs {rhs.full_significand()}; auto exp_rhs {rhs.biased_exponent()}; detail::normalize(sig_rhs, exp_rhs); - auto rhs_components {detail::decimal64_components{sig_rhs, exp_rhs, rhs.isneg()}}; - const auto result {detail::d64_sub_impl(lhs_components.sig, lhs_components.exp, lhs_components.sign, - rhs_components.sig, rhs_components.exp, rhs_components.sign, - abs_lhs_bigger)}; - - return {result.sig, result.exp, result.sign}; + return {detail::d64_sub_impl(final_sig_lhs, exp_lhs, (lhs < 0), + sig_rhs, exp_rhs, rhs.isneg(), + abs_lhs_bigger)}; } constexpr auto operator*(decimal64 lhs, decimal64 rhs) noexcept -> decimal64 From bb43e5979e04e0cb53d8a8d5706801183a5386de Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 24 Jun 2024 08:49:22 -0400 Subject: [PATCH 13/45] Further simplification to operator+ --- include/boost/decimal/decimal32_fast.hpp | 6 +++--- include/boost/decimal/decimal64.hpp | 21 +++++++++++---------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/include/boost/decimal/decimal32_fast.hpp b/include/boost/decimal/decimal32_fast.hpp index 3b71be722..a1c347dfb 100644 --- a/include/boost/decimal/decimal32_fast.hpp +++ b/include/boost/decimal/decimal32_fast.hpp @@ -795,7 +795,7 @@ template constexpr auto operator+(decimal32_fast lhs, Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32_fast) { - using promoted_significand_type = std::conditional_t::digits10 < std::numeric_limits::digits10, decimal32::significand_type, detail::make_unsigned_t>; + using promoted_significand_type = std::conditional_t::digits10 < std::numeric_limits::digits10, decimal32_fast::significand_type, detail::make_unsigned_t>; #ifndef BOOST_DECIMAL_FAST_MATH if (isnan(lhs) || isinf(lhs)) @@ -876,7 +876,7 @@ template constexpr auto operator-(decimal32_fast lhs, Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32_fast) { - using promoted_significand_type = std::conditional_t::digits10 < std::numeric_limits::digits10, decimal32::significand_type, detail::make_unsigned_t>; + using promoted_significand_type = std::conditional_t::digits10 < std::numeric_limits::digits10, decimal32_fast::significand_type, detail::make_unsigned_t>; #ifndef BOOST_DECIMAL_FAST_MATH if (isinf(lhs) || isnan(lhs)) @@ -908,7 +908,7 @@ template constexpr auto operator-(Integer lhs, decimal32_fast rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32_fast) { - using promoted_significand_type = std::conditional_t::digits10 < std::numeric_limits::digits10, decimal32::significand_type, detail::make_unsigned_t>; + using promoted_significand_type = std::conditional_t::digits10 < std::numeric_limits::digits10, decimal32_fast::significand_type, detail::make_unsigned_t>; #ifndef BOOST_DECIMAL_FAST_MATH if (isinf(rhs) || isnan(rhs)) diff --git a/include/boost/decimal/decimal64.hpp b/include/boost/decimal/decimal64.hpp index 1525be2a7..99ff780b2 100644 --- a/include/boost/decimal/decimal64.hpp +++ b/include/boost/decimal/decimal64.hpp @@ -1226,6 +1226,8 @@ template constexpr auto operator+(decimal64 lhs, Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal64) { + using promoted_significand_type = std::conditional_t::digits10 < std::numeric_limits::digits10, decimal64::significand_type, detail::make_unsigned_t>; + #ifndef BOOST_DECIMAL_FAST_MATH if (isnan(lhs) || isinf(lhs)) { @@ -1238,18 +1240,19 @@ constexpr auto operator+(decimal64 lhs, Integer rhs) noexcept { lhs_bigger = !lhs_bigger; } - bool abs_lhs_bigger {abs(lhs) > detail::make_positive_unsigned(rhs)}; + + auto sig_rhs {static_cast(detail::make_positive_unsigned(rhs))}; + bool abs_lhs_bigger {abs(lhs) > sig_rhs}; auto sig_lhs {lhs.full_significand()}; auto exp_lhs {lhs.biased_exponent()}; detail::normalize(sig_lhs, exp_lhs); auto lhs_components {detail::decimal64_components{sig_lhs, exp_lhs, lhs.isneg()}}; - auto sig_rhs {static_cast(detail::make_positive_unsigned(rhs))}; - std::int32_t exp_rhs {0}; + decimal64::biased_exponent_type exp_rhs {0}; detail::normalize(sig_rhs, exp_rhs); - auto unsigned_sig_rhs {static_cast(detail::make_positive_unsigned(sig_rhs))}; - auto rhs_components {detail::decimal64_components{unsigned_sig_rhs, exp_rhs, (rhs < 0)}}; + const auto final_sig_rhs {static_cast(sig_rhs)}; + auto rhs_components {detail::decimal64_components{final_sig_rhs, exp_rhs, (rhs < 0)}}; if (!lhs_bigger) { @@ -1266,11 +1269,9 @@ constexpr auto operator+(decimal64 lhs, Integer rhs) noexcept if (!lhs_components.sign && rhs_components.sign) { - detail::decimal64_components result {}; - result = detail::d64_sub_impl(lhs_components.sig, lhs_components.exp, lhs_components.sign, - rhs_components.sig, rhs_components.exp, rhs_components.sign, - abs_lhs_bigger); - return decimal64(result.sig, result.exp, result.sign); + return detail::d64_sub_impl(lhs_components.sig, lhs_components.exp, lhs_components.sign, + rhs_components.sig, rhs_components.exp, rhs_components.sign, + abs_lhs_bigger); } else { From 76f7130014c380dcd9e9feebce9842ef49d19961 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 24 Jun 2024 09:39:51 -0400 Subject: [PATCH 14/45] Simplify 64-bit sub impl --- include/boost/decimal/detail/sub_impl.hpp | 61 +++++++++++------------ 1 file changed, 29 insertions(+), 32 deletions(-) diff --git a/include/boost/decimal/detail/sub_impl.hpp b/include/boost/decimal/detail/sub_impl.hpp index e56379ddd..2d0f42434 100644 --- a/include/boost/decimal/detail/sub_impl.hpp +++ b/include/boost/decimal/detail/sub_impl.hpp @@ -22,7 +22,7 @@ BOOST_DECIMAL_FORCE_INLINE constexpr auto sub_impl(T lhs_sig, U lhs_exp, bool lh T rhs_sig, U rhs_exp, bool rhs_sign, bool abs_lhs_bigger) noexcept -> ReturnType { - using sub_type = detail::make_signed_t; + using sub_type = std::int_fast32_t; auto delta_exp {lhs_exp > rhs_exp ? lhs_exp - rhs_exp : rhs_exp - lhs_exp}; auto signed_sig_lhs {detail::make_signed_value(lhs_sig, lhs_sign)}; @@ -85,14 +85,16 @@ BOOST_DECIMAL_FORCE_INLINE constexpr auto sub_impl(T lhs_sig, U lhs_exp, bool lh return {res_sig, new_exp, new_sign}; } -template -constexpr auto d64_sub_impl(T1 lhs_sig, std::int32_t lhs_exp, bool lhs_sign, - T2 rhs_sig, std::int32_t rhs_exp, bool rhs_sign, +template +constexpr auto d64_sub_impl(T lhs_sig, U lhs_exp, bool lhs_sign, + T rhs_sig, U rhs_exp, bool rhs_sign, bool abs_lhs_bigger) noexcept -> ReturnType { + using sub_type = std::int_fast64_t; + auto delta_exp {lhs_exp > rhs_exp ? lhs_exp - rhs_exp : rhs_exp - lhs_exp}; - auto signed_sig_lhs {detail::make_signed_value(lhs_sig, lhs_sign)}; - auto signed_sig_rhs {detail::make_signed_value(rhs_sig, rhs_sign)}; + auto signed_sig_lhs {static_cast(detail::make_signed_value(lhs_sig, lhs_sign))}; + auto signed_sig_rhs {static_cast(detail::make_signed_value(rhs_sig, rhs_sign))}; if (delta_exp > detail::precision_v + 1) { @@ -117,36 +119,31 @@ constexpr auto d64_sub_impl(T1 lhs_sig, std::int32_t lhs_exp, bool lhs_sign, --delta_exp; --exp_bigger; } - else if (delta_exp >= 2) + else { - sig_bigger *= 100; - delta_exp -= 2; - exp_bigger -= 2; - } + if (delta_exp >= 2) + { + sig_bigger *= 100; + delta_exp -= 2; + exp_bigger -= 2; + } - while (delta_exp > 1) - { - sig_smaller /= 10; - --delta_exp; - } + if (delta_exp > 1) + { + sig_smaller /= pow10>(delta_exp - 1); + delta_exp = 1; + } - if (delta_exp == 1) - { - detail::fenv_round(sig_smaller, smaller_sign); + if (delta_exp == 1) + { + detail::fenv_round(sig_smaller, smaller_sign); + } } // Both of the significands are less than 9'999'999'999'999'999, so we can safely // cast them to signed 64-bit ints to calculate the new significand - std::int64_t new_sig {}; // NOLINT : Value is never used but can't leave uninitialized in constexpr function - - if (rhs_sign && !lhs_sign) - { - new_sig = signed_sig_lhs + signed_sig_rhs; - } - else - { - new_sig = signed_sig_lhs - signed_sig_rhs; - } + const sub_type new_sig {rhs_sign && !lhs_sign ? signed_sig_lhs + signed_sig_rhs : + signed_sig_lhs - signed_sig_rhs}; const auto new_exp {abs_lhs_bigger ? lhs_exp : rhs_exp}; const auto new_sign {new_sig < 0}; @@ -226,8 +223,8 @@ constexpr auto d128_sub_impl(T1 lhs_sig, std::int32_t lhs_exp, bool lhs_sign, return {res_sig, new_exp, new_sign}; } -} -} -} +} // namespace detail +} // namespace decimal +} // namespace boost #endif //BOOST_DECIMAL_DETAIL_SUB_IMPL_HPP From e52ede374ac200fbada492cf616998b2db74fc5a Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 24 Jun 2024 10:14:35 -0400 Subject: [PATCH 15/45] Add decimal64_fast riemann zeta testing --- test/test_zeta.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/test/test_zeta.cpp b/test/test_zeta.cpp index 62b9e4f6d..d36b0225e 100644 --- a/test/test_zeta.cpp +++ b/test/test_zeta.cpp @@ -403,6 +403,26 @@ int main() BOOST_TEST(result_is_ok); } + { + using decimal_type = ::boost::decimal::decimal64_fast; + + const bool result_rz64_is_ok = local::test_riemann_zeta(256, 1.1L, 12.3L); + + result_is_ok = (result_rz64_is_ok && result_is_ok); + + BOOST_TEST(result_is_ok); + } + + { + using decimal_type = ::boost::decimal::decimal64_fast; + + const bool result_rz64_is_ok = local::test_riemann_zeta(1024, 1.01L, 1.1L); + + result_is_ok = (result_rz64_is_ok && result_is_ok); + + BOOST_TEST(result_is_ok); + } + { const auto result_rz_128_lo_is_ok = local::test_riemann_zeta_128_lo(4096); const auto result_rz_128_hi_is_ok = local::test_riemann_zeta_128_hi(4096); From ead73a35612f32885e424948c9aaa7899d1ce983 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 24 Jun 2024 10:14:44 -0400 Subject: [PATCH 16/45] Fix linker error --- include/boost/decimal/detail/cmath/impl/riemann_zeta_impl.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/boost/decimal/detail/cmath/impl/riemann_zeta_impl.hpp b/include/boost/decimal/detail/cmath/impl/riemann_zeta_impl.hpp index 86805ecda..702b63f57 100644 --- a/include/boost/decimal/detail/cmath/impl/riemann_zeta_impl.hpp +++ b/include/boost/decimal/detail/cmath/impl/riemann_zeta_impl.hpp @@ -168,6 +168,9 @@ constexpr typename riemann_zeta_table_imp::d32_fast_coeffs_t riemann_zeta_tab template constexpr typename riemann_zeta_table_imp::d64_coeffs_t riemann_zeta_table_imp::d64_coeffs; +template +constexpr typename riemann_zeta_table_imp::d64_fast_coeffs_t riemann_zeta_table_imp::d64_fast_coeffs; + template constexpr typename riemann_zeta_table_imp::d128_coeffs_t riemann_zeta_table_imp::d128_coeffs; From 2a7dec68321c964dca7336451b802c88e9392be6 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 24 Jun 2024 10:18:55 -0400 Subject: [PATCH 17/45] Further changes to decimal64_fast operator+ --- include/boost/decimal/decimal64_fast.hpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/include/boost/decimal/decimal64_fast.hpp b/include/boost/decimal/decimal64_fast.hpp index ae95cedb4..222d9f81f 100644 --- a/include/boost/decimal/decimal64_fast.hpp +++ b/include/boost/decimal/decimal64_fast.hpp @@ -45,7 +45,7 @@ class decimal64_fast final public: using significand_type = std::uint_fast64_t; using exponent_type = std::uint_fast16_t; - using biased_exponent_type = std::int32_t; + using biased_exponent_type = std::int_fast32_t; private: // In regular decimal64 we have to decode the significand end exponent @@ -914,6 +914,8 @@ template constexpr auto operator+(decimal64_fast lhs, Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal64_fast) { + using promoted_significand_type = std::conditional_t::digits10 < std::numeric_limits::digits10, decimal64_fast::significand_type, detail::make_unsigned_t>; + #ifndef BOOST_DECIMAL_FAST_MATH if (isnan(lhs) || isinf(lhs)) { @@ -926,14 +928,14 @@ constexpr auto operator+(decimal64_fast lhs, Integer rhs) noexcept { lhs_bigger = !lhs_bigger; } - bool abs_lhs_bigger {abs(lhs) > detail::make_positive_unsigned(rhs)}; + auto sig_rhs {static_cast(detail::make_positive_unsigned(rhs))}; + bool abs_lhs_bigger {abs(lhs) > sig_rhs}; auto lhs_components {detail::decimal64_fast_components{lhs.significand_, lhs.biased_exponent(), lhs.isneg()}}; - auto sig_rhs {static_cast(detail::make_positive_unsigned(rhs))}; - std::int32_t exp_rhs {0}; + decimal64_fast::biased_exponent_type exp_rhs {0}; detail::normalize(sig_rhs, exp_rhs); - auto unsigned_sig_rhs {static_cast(detail::make_positive_unsigned(sig_rhs))}; + auto unsigned_sig_rhs {static_cast(sig_rhs)}; auto rhs_components {detail::decimal64_fast_components{unsigned_sig_rhs, exp_rhs, (rhs < 0)}}; if (!lhs_bigger) @@ -951,11 +953,9 @@ constexpr auto operator+(decimal64_fast lhs, Integer rhs) noexcept if (!lhs_components.sign && rhs_components.sign) { - detail::decimal64_fast_components result {}; - result = detail::d64_sub_impl(lhs_components.sig, lhs_components.exp, lhs_components.sign, - rhs_components.sig, rhs_components.exp, rhs_components.sign, - abs_lhs_bigger); - return {result.sig, result.exp, result.sign}; + return detail::d64_sub_impl(lhs_components.sig, lhs_components.exp, lhs_components.sign, + rhs_components.sig, rhs_components.exp, rhs_components.sign, + abs_lhs_bigger); } else { From 07ec0e56366c0ccbc86cf142a8e5247700c64bb5 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 24 Jun 2024 10:39:36 -0400 Subject: [PATCH 18/45] Simplify decimal64_fast operators- --- include/boost/decimal/decimal64_fast.hpp | 42 ++++++++++-------------- 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/include/boost/decimal/decimal64_fast.hpp b/include/boost/decimal/decimal64_fast.hpp index 222d9f81f..96143ed72 100644 --- a/include/boost/decimal/decimal64_fast.hpp +++ b/include/boost/decimal/decimal64_fast.hpp @@ -1003,6 +1003,8 @@ template constexpr auto operator-(decimal64_fast lhs, Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal64_fast) { + using promoted_significand_type = std::conditional_t::digits10 < std::numeric_limits::digits10, decimal64_fast::significand_type, detail::make_unsigned_t>; + #ifndef BOOST_DECIMAL_FAST_MATH if (isinf(lhs) || isnan(lhs)) { @@ -1015,28 +1017,24 @@ constexpr auto operator-(decimal64_fast lhs, Integer rhs) noexcept return lhs + detail::make_positive_unsigned(rhs); } + auto sig_rhs {static_cast(detail::make_positive_unsigned(rhs))}; const bool abs_lhs_bigger {abs(lhs) > detail::make_positive_unsigned(rhs)}; - auto lhs_components {detail::decimal64_fast_components{lhs.significand_, lhs.biased_exponent(), lhs.isneg()}}; - - auto sig_rhs {static_cast(detail::make_positive_unsigned(rhs))}; - std::int32_t exp_rhs {0}; + decimal64_fast::biased_exponent_type exp_rhs {0}; detail::normalize(sig_rhs, exp_rhs); - auto unsigned_sig_rhs = detail::shrink_significand(detail::make_positive_unsigned(sig_rhs), exp_rhs); - auto rhs_components {detail::decimal64_fast_components{unsigned_sig_rhs, exp_rhs, (rhs < 0)}}; + const auto final_sig_rhs {static_cast(sig_rhs)}; - const auto result {detail::d64_sub_impl( - lhs_components.sig, lhs_components.exp, lhs_components.sign, - rhs_components.sig, rhs_components.exp, rhs_components.sign, - abs_lhs_bigger)}; - - return {result.sig, result.exp, result.sign}; + return {detail::d64_sub_impl(lhs.significand_, lhs.biased_exponent(), lhs.sign_, + final_sig_rhs, exp_rhs, (rhs < 0), + abs_lhs_bigger)}; } template constexpr auto operator-(Integer lhs, decimal64_fast rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal64_fast) { + using promoted_significand_type = std::conditional_t::digits10 < std::numeric_limits::digits10, decimal64::significand_type, detail::make_unsigned_t>; + #ifndef BOOST_DECIMAL_FAST_MATH if (isinf(rhs) || isnan(rhs)) { @@ -1049,22 +1047,16 @@ constexpr auto operator-(Integer lhs, decimal64_fast rhs) noexcept return lhs + (-rhs); } - const bool abs_lhs_bigger {detail::make_positive_unsigned(lhs) > abs(rhs)}; + auto sig_lhs {static_cast(detail::make_positive_unsigned(lhs))}; + const bool abs_lhs_bigger {sig_lhs > abs(rhs)}; - auto sig_lhs {static_cast(detail::make_positive_unsigned(lhs))}; - std::int32_t exp_lhs {0}; + decimal64_fast::biased_exponent_type exp_lhs {0}; detail::normalize(sig_lhs, exp_lhs); - auto unsigned_sig_lhs = detail::shrink_significand(detail::make_positive_unsigned(sig_lhs), exp_lhs); - auto lhs_components {detail::decimal64_fast_components{unsigned_sig_lhs, exp_lhs, (lhs < 0)}}; - - auto rhs_components {detail::decimal64_fast_components{rhs.significand_, rhs.biased_exponent(), rhs.isneg()}}; + const auto final_sig_lhs {static_cast(sig_lhs)}; - const auto result {detail::d64_sub_impl( - lhs_components.sig, lhs_components.exp, lhs_components.sign, - rhs_components.sig, rhs_components.exp, rhs_components.sign, - abs_lhs_bigger)}; - - return {result.sig, result.exp, result.sign}; + return {detail::d64_sub_impl(final_sig_lhs, exp_lhs, (lhs < 0), + rhs.significand_, rhs.biased_exponent(), rhs.sign_, + abs_lhs_bigger)}; } constexpr auto operator*(decimal64_fast lhs, decimal64_fast rhs) noexcept -> decimal64_fast From b293a74ffab4795dc61fe4291426820f95c5d18c Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 24 Jun 2024 11:07:50 -0400 Subject: [PATCH 19/45] Add basic operator significand promotion function --- .../decimal/detail/promote_significand.hpp | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 include/boost/decimal/detail/promote_significand.hpp diff --git a/include/boost/decimal/detail/promote_significand.hpp b/include/boost/decimal/detail/promote_significand.hpp new file mode 100644 index 000000000..b53149d37 --- /dev/null +++ b/include/boost/decimal/detail/promote_significand.hpp @@ -0,0 +1,35 @@ +// Copyright 2024 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_DECIMAL_DETAIL_PROMOTE_SIGNIFICAND_HPP +#define BOOST_DECIMAL_DETAIL_PROMOTE_SIGNIFICAND_HPP + +#include +#include +#include +#include + +namespace boost { +namespace decimal { +namespace detail { + +namespace impl { + +template +struct promote_significand +{ + using type = std::conditional_t::digits10 < std::numeric_limits::digits10, + typename DecimalType::significand_type, detail::make_unsigned_t>; +}; + +} // namespace impl + +template +using promote_significand_t = typename impl::promote_significand::type; + +} // namespace detail +} // namespace decimal +} // namespace boost + +#endif //BOOST_DECIMAL_DETAIL_PROMOTE_SIGNIFICAND_HPP From 376aae9816b35ca6665a8f52a8193e23594dddfb Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 24 Jun 2024 12:00:29 -0400 Subject: [PATCH 20/45] Add a conditional significantly simpler mul_impl --- include/boost/decimal/detail/mul_impl.hpp | 36 +++++++++++++++++++---- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/include/boost/decimal/detail/mul_impl.hpp b/include/boost/decimal/detail/mul_impl.hpp index 1a03a051a..3ea524570 100644 --- a/include/boost/decimal/detail/mul_impl.hpp +++ b/include/boost/decimal/detail/mul_impl.hpp @@ -19,10 +19,34 @@ namespace boost { namespace decimal { namespace detail { -template -BOOST_DECIMAL_FORCE_INLINE constexpr auto mul_impl(T1 lhs_sig, std::int32_t lhs_exp, bool lhs_sign, - T2 rhs_sig, std::int32_t rhs_exp, bool rhs_sign) noexcept -> ReturnType +// Each type has two different multiplication impls +// 1) Returns a decimal type and lets the constructor handle with shrinking the significand +// 2) + +template +BOOST_DECIMAL_FORCE_INLINE constexpr auto mul_impl(T lhs_sig, U lhs_exp, bool lhs_sign, + T rhs_sig, U rhs_exp, bool rhs_sign) noexcept -> std::enable_if_t, ReturnType> { + using mul_type = std::uint_fast64_t; + + bool sign {lhs_sign != rhs_sign}; + auto res_sig {static_cast(lhs_sig) * static_cast(rhs_sig)}; + auto res_exp {lhs_exp + rhs_exp}; + + if (res_sig == 0) + { + sign = false; + } + + return {res_sig, res_exp, sign}; +} + +template +BOOST_DECIMAL_FORCE_INLINE constexpr auto mul_impl(T lhs_sig, U lhs_exp, bool lhs_sign, + T rhs_sig, U rhs_exp, bool rhs_sign) noexcept -> std::enable_if_t, ReturnType> +{ + using mul_type = std::uint_fast64_t; + #ifdef BOOST_DECIMAL_DEBUG std::cerr << "sig lhs: " << sig_lhs << "\nexp lhs: " << exp_lhs @@ -37,15 +61,15 @@ BOOST_DECIMAL_FORCE_INLINE constexpr auto mul_impl(T1 lhs_sig, std::int32_t lhs_ // // We use a 64 bit resultant significand because the two 23-bit unsigned significands will always fit - auto res_sig {static_cast(lhs_sig) * static_cast(rhs_sig)}; + auto res_sig {static_cast(lhs_sig) * static_cast(rhs_sig)}; auto res_exp {lhs_exp + rhs_exp}; // We don't need to use the regular binary search tree detail::num_digits(res_sig) // because we know that res_sig must be [1'000'000^2, 9'999'999^2] which only differ by one order // of magnitude in their number of digits const auto sig_dig {res_sig >= UINT64_C(10000000000000) ? 14 : 13}; - constexpr auto max_dig {std::numeric_limits::digits10}; - res_sig /= detail::pow10(static_cast(sig_dig - max_dig)); + constexpr auto max_dig {std::numeric_limits::digits10}; + res_sig /= detail::pow10(static_cast(sig_dig - max_dig)); res_exp += sig_dig - max_dig; const auto res_sig_32 {static_cast(res_sig)}; From 2ad339ccb383e1872840b396a90ede8cdb32aa4c Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 24 Jun 2024 12:00:54 -0400 Subject: [PATCH 21/45] Improve decimal32_fast operator* --- include/boost/decimal/decimal32_fast.hpp | 30 ++++++++++-------------- 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/include/boost/decimal/decimal32_fast.hpp b/include/boost/decimal/decimal32_fast.hpp index a1c347dfb..dc8daff98 100644 --- a/include/boost/decimal/decimal32_fast.hpp +++ b/include/boost/decimal/decimal32_fast.hpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -795,7 +796,7 @@ template constexpr auto operator+(decimal32_fast lhs, Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32_fast) { - using promoted_significand_type = std::conditional_t::digits10 < std::numeric_limits::digits10, decimal32_fast::significand_type, detail::make_unsigned_t>; + using promoted_significand_type = detail::promote_significand_t; #ifndef BOOST_DECIMAL_FAST_MATH if (isnan(lhs) || isinf(lhs)) @@ -876,7 +877,7 @@ template constexpr auto operator-(decimal32_fast lhs, Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32_fast) { - using promoted_significand_type = std::conditional_t::digits10 < std::numeric_limits::digits10, decimal32_fast::significand_type, detail::make_unsigned_t>; + using promoted_significand_type = detail::promote_significand_t; #ifndef BOOST_DECIMAL_FAST_MATH if (isinf(lhs) || isnan(lhs)) @@ -908,7 +909,7 @@ template constexpr auto operator-(Integer lhs, decimal32_fast rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32_fast) { - using promoted_significand_type = std::conditional_t::digits10 < std::numeric_limits::digits10, decimal32_fast::significand_type, detail::make_unsigned_t>; + using promoted_significand_type = detail::promote_significand_t; #ifndef BOOST_DECIMAL_FAST_MATH if (isinf(rhs) || isnan(rhs)) @@ -948,18 +949,18 @@ constexpr auto operator*(decimal32_fast lhs, decimal32_fast rhs) noexcept -> dec } #endif - const auto result {detail::mul_impl( + return {detail::mul_impl( lhs.significand_, lhs.biased_exponent(), lhs.sign_, rhs.significand_, rhs.biased_exponent(), rhs.sign_ )}; - - return {result.sig, result.exp, result.sign}; } template constexpr auto operator*(decimal32_fast lhs, Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32_fast) { + using promoted_significand_type = detail::promote_significand_t; + #ifndef BOOST_DECIMAL_FAST_MATH if (isnan(lhs) || isinf(lhs)) { @@ -967,20 +968,13 @@ constexpr auto operator*(decimal32_fast lhs, Integer rhs) noexcept } #endif - auto lhs_components {detail::decimal32_fast_components{lhs.significand_, lhs.biased_exponent(), lhs.sign_}}; - - auto sig_rhs {rhs}; - std::int32_t exp_rhs {0}; + auto sig_rhs {static_cast(detail::make_positive_unsigned(rhs))}; + decimal32_fast::biased_exponent_type exp_rhs {0}; detail::normalize(sig_rhs, exp_rhs); - auto unsigned_sig_rhs {detail::shrink_significand(detail::make_positive_unsigned(sig_rhs), exp_rhs)}; - auto rhs_components {detail::decimal32_fast_components{unsigned_sig_rhs, exp_rhs, (rhs < 0)}}; - - const auto result {detail::mul_impl( - lhs_components.sig, lhs_components.exp, lhs_components.sign, - rhs_components.sig, rhs_components.exp, rhs_components.sign - )}; + const auto final_sig_rhs {static_cast(sig_rhs)}; - return {result.sig, result.exp, result.sign}; + return {detail::mul_impl(lhs.significand_, lhs.biased_exponent(), lhs.sign_, + final_sig_rhs, exp_rhs, (rhs < 0))}; } template From 85aedca458a4d984bb184066bd023f72549041ef Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 24 Jun 2024 13:27:48 -0400 Subject: [PATCH 22/45] Improve decimal32 operator* --- include/boost/decimal/decimal32.hpp | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/include/boost/decimal/decimal32.hpp b/include/boost/decimal/decimal32.hpp index 01b9531ad..712e11bb7 100644 --- a/include/boost/decimal/decimal32.hpp +++ b/include/boost/decimal/decimal32.hpp @@ -36,6 +36,7 @@ #include #include #include +#include #ifndef BOOST_DECIMAL_BUILD_MODULE @@ -874,7 +875,7 @@ template constexpr auto operator+(decimal32 lhs, Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32) { - using promoted_significand_type = std::conditional_t::digits10 < std::numeric_limits::digits10, decimal32::significand_type, detail::make_unsigned_t>; + using promoted_significand_type = detail::promote_significand_t; #ifndef BOOST_DECIMAL_FAST_MATH if (isnan(lhs) || isinf(lhs)) @@ -1002,7 +1003,7 @@ template constexpr auto operator-(decimal32 lhs, Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32) { - using promoted_significand_type = std::conditional_t::digits10 < std::numeric_limits::digits10, decimal32::significand_type, detail::make_unsigned_t>; + using promoted_significand_type = detail::promote_significand_t; #ifndef BOOST_DECIMAL_FAST_MATH if (isinf(lhs) || isnan(lhs)) @@ -1036,7 +1037,7 @@ template constexpr auto operator-(Integer lhs, decimal32 rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32) { - using promoted_significand_type = std::conditional_t::digits10 < std::numeric_limits::digits10, decimal32::significand_type, detail::make_unsigned_t>; + using promoted_significand_type = detail::promote_significand_t; #ifndef BOOST_DECIMAL_FAST_MATH if (isinf(rhs) || isnan(rhs)) @@ -1660,15 +1661,16 @@ constexpr auto operator*(decimal32 lhs, decimal32 rhs) noexcept -> decimal32 auto exp_rhs {rhs.biased_exponent()}; detail::normalize(sig_rhs, exp_rhs); - const auto result {detail::mul_impl(sig_lhs, exp_lhs, lhs.isneg(), sig_rhs, exp_rhs, rhs.isneg())}; - - return {result.sig, result.exp, result.sign}; + return {detail::mul_impl(sig_lhs, exp_lhs, lhs.isneg(), + sig_rhs, exp_rhs, rhs.isneg())}; } template constexpr auto operator*(decimal32 lhs, Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal32) { + using promoted_significand_type = detail::promote_significand_t; + #ifndef BOOST_DECIMAL_FAST_MATH if (isnan(lhs) || isinf(lhs)) { @@ -1679,19 +1681,14 @@ constexpr auto operator*(decimal32 lhs, Integer rhs) noexcept auto sig_lhs {lhs.full_significand()}; auto exp_lhs {lhs.biased_exponent()}; detail::normalize(sig_lhs, exp_lhs); - auto lhs_components {detail::decimal32_components{sig_lhs, exp_lhs, lhs.isneg()}}; - auto sig_rhs {rhs}; - std::int32_t exp_rhs {0}; + auto sig_rhs {static_cast(detail::make_positive_unsigned(rhs))}; + decimal32::biased_exponent_type exp_rhs {0}; detail::normalize(sig_rhs, exp_rhs); - auto unsigned_sig_rhs {detail::shrink_significand(detail::make_positive_unsigned(sig_rhs), exp_rhs)}; - auto rhs_components {detail::decimal32_components{unsigned_sig_rhs, exp_rhs, (rhs < 0)}}; - - const auto result {detail::mul_impl( - lhs_components.sig, lhs_components.exp, lhs_components.sign, - rhs_components.sig, rhs_components.exp, rhs_components.sign)}; + auto final_sig_rhs {static_cast(sig_rhs)}; - return {result.sig, result.exp, result.sign}; + return{detail::mul_impl(sig_lhs, exp_lhs, lhs.isneg(), + final_sig_rhs, exp_rhs, (rhs < 0))}; } template From f89b3d8ed56794483c881fa1e31ca7cb6b207392 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 24 Jun 2024 14:23:17 -0400 Subject: [PATCH 23/45] Add simplified 64 bit mul impl --- include/boost/decimal/detail/mul_impl.hpp | 36 +++++++++++++++++++---- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/include/boost/decimal/detail/mul_impl.hpp b/include/boost/decimal/detail/mul_impl.hpp index 3ea524570..ab8a2d628 100644 --- a/include/boost/decimal/detail/mul_impl.hpp +++ b/include/boost/decimal/detail/mul_impl.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #ifndef BOOST_DECIMAL_BUILD_MODULE #include @@ -21,7 +22,7 @@ namespace detail { // Each type has two different multiplication impls // 1) Returns a decimal type and lets the constructor handle with shrinking the significand -// 2) +// 2) Returns a struct of the constituent components (used with FMAs) template BOOST_DECIMAL_FORCE_INLINE constexpr auto mul_impl(T lhs_sig, U lhs_exp, bool lhs_sign, @@ -87,9 +88,32 @@ BOOST_DECIMAL_FORCE_INLINE constexpr auto mul_impl(T lhs_sig, U lhs_exp, bool lh return {res_sig_32, res_exp, sign}; } -template -constexpr auto d64_mul_impl(T1 lhs_sig, std::int32_t lhs_exp, bool lhs_sign, - T2 rhs_sig, std::int32_t rhs_exp, bool rhs_sign) noexcept -> ReturnType +template +BOOST_DECIMAL_FORCE_INLINE constexpr auto d64_mul_impl(T lhs_sig, U lhs_exp, bool lhs_sign, + T rhs_sig, U rhs_exp, bool rhs_sign) noexcept + -> std::enable_if_t, ReturnType> +{ + #ifdef BOOST_DECIMAL_HAS_INT128 + using unsigned_int128_type = boost::decimal::detail::uint128_t; + #else + using unsigned_int128_type = boost::decimal::detail::uint128; + #endif + + bool sign {lhs_sign != rhs_sign}; + + // Once we have the normalized significands and exponents all we have to do is + // multiply the significands and add the exponents + + auto res_sig {static_cast(lhs_sig) * static_cast(rhs_sig)}; + auto res_exp {lhs_exp + rhs_exp}; + + return {res_sig, res_exp, sign}; +} + +template +BOOST_DECIMAL_FORCE_INLINE constexpr auto d64_mul_impl(T lhs_sig, U lhs_exp, bool lhs_sign, + T rhs_sig, U rhs_exp, bool rhs_sign) noexcept + -> std::enable_if_t, ReturnType> { #ifdef BOOST_DECIMAL_HAS_INT128 using unsigned_int128_type = boost::decimal::detail::uint128_t; @@ -115,11 +139,11 @@ constexpr auto d64_mul_impl(T1 lhs_sig, std::int32_t lhs_exp, bool lhs_sign, auto res_exp {lhs_exp + rhs_exp}; const auto sig_dig {res_sig >= comp_value ? 32 : 31}; - constexpr auto max_dig {std::numeric_limits::digits10}; + constexpr auto max_dig {std::numeric_limits::digits10}; res_sig /= detail::pow10(static_cast(sig_dig - max_dig)); res_exp += sig_dig - max_dig; - const auto res_sig_64 {static_cast(res_sig)}; + const auto res_sig_64 {static_cast(res_sig)}; #ifdef BOOST_DECIMAL_DEBUG std::cerr << "\nres sig: " << res_sig_64 From 30e4acfc09a9328967e100b1f7ccfce9a5a00bbb Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 24 Jun 2024 14:23:32 -0400 Subject: [PATCH 24/45] Simplify operators* --- include/boost/decimal/decimal64.hpp | 29 +++++++++++------------- include/boost/decimal/decimal64_fast.hpp | 26 ++++++++++----------- 2 files changed, 25 insertions(+), 30 deletions(-) diff --git a/include/boost/decimal/decimal64.hpp b/include/boost/decimal/decimal64.hpp index 99ff780b2..773a1118a 100644 --- a/include/boost/decimal/decimal64.hpp +++ b/include/boost/decimal/decimal64.hpp @@ -38,6 +38,7 @@ #include #include #include +#include #ifndef BOOST_DECIMAL_BUILD_MODULE @@ -1226,7 +1227,7 @@ template constexpr auto operator+(decimal64 lhs, Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal64) { - using promoted_significand_type = std::conditional_t::digits10 < std::numeric_limits::digits10, decimal64::significand_type, detail::make_unsigned_t>; + using promoted_significand_type = detail::promote_significand_t; #ifndef BOOST_DECIMAL_FAST_MATH if (isnan(lhs) || isinf(lhs)) @@ -1324,7 +1325,7 @@ template constexpr auto operator-(decimal64 lhs, Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal64) { - using promoted_significand_type = std::conditional_t::digits10 < std::numeric_limits::digits10, decimal64::significand_type, detail::make_unsigned_t>; + using promoted_significand_type = detail::promote_significand_t; #ifndef BOOST_DECIMAL_FAST_MATH if (isinf(lhs) || isnan(lhs)) @@ -1358,7 +1359,7 @@ template constexpr auto operator-(Integer lhs, decimal64 rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal64) { - using promoted_significand_type = std::conditional_t::digits10 < std::numeric_limits::digits10, decimal64::significand_type, detail::make_unsigned_t>; + using promoted_significand_type = detail::promote_significand_t; #ifndef BOOST_DECIMAL_FAST_MATH if (isinf(rhs) || isnan(rhs)) @@ -1408,16 +1409,16 @@ constexpr auto operator*(decimal64 lhs, decimal64 rhs) noexcept -> decimal64 auto rhs_exp {rhs.biased_exponent()}; detail::normalize(rhs_sig, rhs_exp); - const auto result {detail::d64_mul_impl(lhs_sig, lhs_exp, lhs.isneg(), - rhs_sig, rhs_exp, rhs.isneg())}; - - return {result.sig, result.exp, result.sign}; + return {detail::d64_mul_impl(lhs_sig, lhs_exp, lhs.isneg(), + rhs_sig, rhs_exp, rhs.isneg())}; } template constexpr auto operator*(decimal64 lhs, Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal64) { + using promoted_significand_type = detail::promote_significand_t; + #ifndef BOOST_DECIMAL_FAST_MATH if (isnan(lhs) || isinf(lhs)) { @@ -1428,18 +1429,14 @@ constexpr auto operator*(decimal64 lhs, Integer rhs) noexcept auto lhs_sig {lhs.full_significand()}; auto lhs_exp {lhs.biased_exponent()}; detail::normalize(lhs_sig, lhs_exp); - auto lhs_components {detail::decimal64_components{lhs_sig, lhs_exp, lhs.isneg()}}; - auto rhs_sig {static_cast(detail::make_positive_unsigned(rhs))}; - std::int32_t rhs_exp {0}; + auto rhs_sig {static_cast(detail::make_positive_unsigned(rhs))}; + decimal64::biased_exponent_type rhs_exp {0}; detail::normalize(rhs_sig, rhs_exp); - auto unsigned_sig_rhs {detail::shrink_significand(detail::make_positive_unsigned(rhs_sig), rhs_exp)}; - auto rhs_components {detail::decimal64_components{unsigned_sig_rhs, rhs_exp, (rhs < 0)}}; - - const auto result {detail::d64_mul_impl(lhs_components.sig, lhs_components.exp, lhs_components.sign, - rhs_components.sig, rhs_components.exp, rhs_components.sign)}; + const auto final_rhs_sig {static_cast(rhs_sig)}; - return {result.sig, result.exp, result.sign}; + return {detail::d64_mul_impl(lhs_sig, lhs_exp, lhs.isneg(), + final_rhs_sig, rhs_exp, (rhs < 0))}; } template diff --git a/include/boost/decimal/decimal64_fast.hpp b/include/boost/decimal/decimal64_fast.hpp index 96143ed72..4d6495ee6 100644 --- a/include/boost/decimal/decimal64_fast.hpp +++ b/include/boost/decimal/decimal64_fast.hpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -914,7 +915,7 @@ template constexpr auto operator+(decimal64_fast lhs, Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal64_fast) { - using promoted_significand_type = std::conditional_t::digits10 < std::numeric_limits::digits10, decimal64_fast::significand_type, detail::make_unsigned_t>; + using promoted_significand_type = detail::promote_significand_t; #ifndef BOOST_DECIMAL_FAST_MATH if (isnan(lhs) || isinf(lhs)) @@ -1003,7 +1004,7 @@ template constexpr auto operator-(decimal64_fast lhs, Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal64_fast) { - using promoted_significand_type = std::conditional_t::digits10 < std::numeric_limits::digits10, decimal64_fast::significand_type, detail::make_unsigned_t>; + using promoted_significand_type = detail::promote_significand_t; #ifndef BOOST_DECIMAL_FAST_MATH if (isinf(lhs) || isnan(lhs)) @@ -1033,7 +1034,7 @@ template constexpr auto operator-(Integer lhs, decimal64_fast rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal64_fast) { - using promoted_significand_type = std::conditional_t::digits10 < std::numeric_limits::digits10, decimal64::significand_type, detail::make_unsigned_t>; + using promoted_significand_type = detail::promote_significand_t; #ifndef BOOST_DECIMAL_FAST_MATH if (isinf(rhs) || isnan(rhs)) @@ -1102,6 +1103,8 @@ template constexpr auto operator*(decimal64_fast lhs, Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal64_fast) { + using promoted_significand_type = detail::promote_significand_t; + #ifndef BOOST_DECIMAL_FAST_MATH if (isnan(lhs) || isinf(lhs)) { @@ -1109,20 +1112,15 @@ constexpr auto operator*(decimal64_fast lhs, Integer rhs) noexcept } #endif - auto lhs_components {detail::decimal64_fast_components{lhs.significand_, lhs.biased_exponent(), lhs.isneg()}}; - - auto rhs_sig {static_cast(detail::make_positive_unsigned(rhs))}; - std::int32_t rhs_exp {0}; + auto rhs_sig {static_cast(detail::make_positive_unsigned(rhs))}; + decimal64_fast::biased_exponent_type rhs_exp {0}; detail::normalize(rhs_sig, rhs_exp); - auto unsigned_sig_rhs {detail::shrink_significand(detail::make_positive_unsigned(rhs_sig), rhs_exp)}; - auto rhs_components {detail::decimal64_fast_components{unsigned_sig_rhs, rhs_exp, (rhs < 0)}}; + auto final_rhs_sig {static_cast(rhs_sig)}; - const auto result {detail::d64_mul_impl( - lhs_components.sig, lhs_components.exp, lhs_components.sign, - rhs_components.sig, rhs_components.exp, rhs_components.sign + return {detail::d64_mul_impl( + lhs.significand_, lhs.biased_exponent(), lhs.sign_, + final_rhs_sig, rhs_exp, (rhs < 0) )}; - - return {result.sig, result.exp, result.sign}; } template From 61405c5af1c5a8de2e2534b0f82f21ec7fbad980 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 24 Jun 2024 14:31:36 -0400 Subject: [PATCH 25/45] Fix normalization of 0s --- include/boost/decimal/detail/mul_impl.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/boost/decimal/detail/mul_impl.hpp b/include/boost/decimal/detail/mul_impl.hpp index ab8a2d628..008b17bfc 100644 --- a/include/boost/decimal/detail/mul_impl.hpp +++ b/include/boost/decimal/detail/mul_impl.hpp @@ -107,6 +107,11 @@ BOOST_DECIMAL_FORCE_INLINE constexpr auto d64_mul_impl(T lhs_sig, U lhs_exp, boo auto res_sig {static_cast(lhs_sig) * static_cast(rhs_sig)}; auto res_exp {lhs_exp + rhs_exp}; + if (res_sig == 0) + { + sign = false; + } + return {res_sig, res_exp, sign}; } From 4624fc9264648f725a57aa373835c3f66692241b Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 24 Jun 2024 14:55:44 -0400 Subject: [PATCH 26/45] Fix decimal64_fast type errors --- include/boost/decimal/decimal64_fast.hpp | 4 +--- include/boost/decimal/detail/sub_impl.hpp | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/include/boost/decimal/decimal64_fast.hpp b/include/boost/decimal/decimal64_fast.hpp index 4d6495ee6..f3e212ed4 100644 --- a/include/boost/decimal/decimal64_fast.hpp +++ b/include/boost/decimal/decimal64_fast.hpp @@ -991,13 +991,11 @@ constexpr auto operator-(decimal64_fast lhs, decimal64_fast rhs) noexcept -> dec const bool abs_lhs_bigger {abs(lhs) > abs(rhs)}; - const auto result {detail::d64_sub_impl( + return {detail::d64_sub_impl( lhs.significand_, lhs.biased_exponent(), lhs.sign_, rhs.significand_, rhs.biased_exponent(), rhs.sign_, abs_lhs_bigger )}; - - return {result.sig, result.exp, result.sign}; } template diff --git a/include/boost/decimal/detail/sub_impl.hpp b/include/boost/decimal/detail/sub_impl.hpp index 2d0f42434..ea8e19506 100644 --- a/include/boost/decimal/detail/sub_impl.hpp +++ b/include/boost/decimal/detail/sub_impl.hpp @@ -102,8 +102,8 @@ constexpr auto d64_sub_impl(T lhs_sig, U lhs_exp, bool lhs_sign, // we return the larger of the two // // e.g. 1e20 - 1e-20 = 1e20 - return abs_lhs_bigger ? ReturnType{detail::shrink_significand(lhs_sig, lhs_exp), lhs_exp, false} : - ReturnType{detail::shrink_significand(rhs_sig, rhs_exp), rhs_exp, true}; + return abs_lhs_bigger ? ReturnType{lhs_sig, lhs_exp, false} : + ReturnType{rhs_sig, rhs_exp, true}; } // The two numbers can be subtracted together without special handling From 5d6817c38499ac925ab40f1bc9f9026544ce59bc Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 24 Jun 2024 15:01:05 -0400 Subject: [PATCH 27/45] Make exp a template type --- include/boost/decimal/detail/shrink_significand.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/decimal/detail/shrink_significand.hpp b/include/boost/decimal/detail/shrink_significand.hpp index 6f624fa6a..707d47c7b 100644 --- a/include/boost/decimal/detail/shrink_significand.hpp +++ b/include/boost/decimal/detail/shrink_significand.hpp @@ -19,8 +19,8 @@ namespace boost { namespace decimal { namespace detail { -template -constexpr auto shrink_significand(Integer sig, std::int32_t& exp) noexcept -> TargetType +template +constexpr auto shrink_significand(Integer sig, Exp& exp) noexcept -> TargetType { using Unsigned_Integer = make_unsigned_t; constexpr auto max_digits {std::numeric_limits::digits10}; From e2b783297c7398c2de292770e625d83abab186a7 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 24 Jun 2024 15:43:07 -0400 Subject: [PATCH 28/45] Disable FMAs for now since they need reworked --- include/boost/decimal/detail/cmath/fma.hpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/include/boost/decimal/detail/cmath/fma.hpp b/include/boost/decimal/detail/cmath/fma.hpp index f7ec9bccf..7efffc4c1 100644 --- a/include/boost/decimal/detail/cmath/fma.hpp +++ b/include/boost/decimal/detail/cmath/fma.hpp @@ -14,6 +14,7 @@ namespace boost { namespace decimal { +/* constexpr auto fmad32(decimal32 x, decimal32 y, decimal32 z) noexcept -> decimal32 { // First calculate x * y without rounding @@ -304,35 +305,36 @@ constexpr auto fmad128f(decimal128_fast x, decimal128_fast y, decimal128_fast z) { return x * y + z; } +*/ BOOST_DECIMAL_EXPORT constexpr auto fma(decimal32 x, decimal32 y, decimal32 z) noexcept -> decimal32 { - return fmad32(x, y, z); + return x * y + z; } BOOST_DECIMAL_EXPORT constexpr auto fma(decimal64 x, decimal64 y, decimal64 z) noexcept -> decimal64 { - return fmad64(x, y, z); + return x * y + z; } BOOST_DECIMAL_EXPORT constexpr auto fma(decimal128 x, decimal128 y, decimal128 z) noexcept -> decimal128 { - return fmad128(x, y, z); + return x * y + z; } BOOST_DECIMAL_EXPORT constexpr auto fma(decimal32_fast x, decimal32_fast y, decimal32_fast z) noexcept -> decimal32_fast { - return fmad32f(x, y, z); + return x * y + z; } BOOST_DECIMAL_EXPORT constexpr auto fma(decimal64_fast x, decimal64_fast y, decimal64_fast z) noexcept -> decimal64_fast { - return fmad64f(x, y, z); + return x * y + z; } BOOST_DECIMAL_EXPORT constexpr auto fma(decimal128_fast x, decimal128_fast y, decimal128_fast z) noexcept -> decimal128_fast { - return fmad128f(x, y, z); + return x * y + z; } } //namespace decimal From f1d524d93ad47b7981c79c2f085c598d2558d6a9 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 24 Jun 2024 16:02:02 -0400 Subject: [PATCH 29/45] Fix old clang conversion --- include/boost/decimal/detail/to_integral.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/decimal/detail/to_integral.hpp b/include/boost/decimal/detail/to_integral.hpp index 51e060127..d4a8efa67 100644 --- a/include/boost/decimal/detail/to_integral.hpp +++ b/include/boost/decimal/detail/to_integral.hpp @@ -63,7 +63,7 @@ constexpr auto to_integral(Decimal val) noexcept } else if (expval < 0) { - result /= detail::pow10(abs_exp_val); + result /= detail::pow10(static_cast(abs_exp_val)); } BOOST_DECIMAL_IF_CONSTEXPR (std::is_signed::value) From 2688bdf0e0cb71fa20717a64c6b789ef0ce10335 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 24 Jun 2024 16:23:47 -0400 Subject: [PATCH 30/45] Remove workaround code path --- include/boost/decimal/decimal64_fast.hpp | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/include/boost/decimal/decimal64_fast.hpp b/include/boost/decimal/decimal64_fast.hpp index f3e212ed4..c58c8b474 100644 --- a/include/boost/decimal/decimal64_fast.hpp +++ b/include/boost/decimal/decimal64_fast.hpp @@ -1070,17 +1070,6 @@ constexpr auto operator*(decimal64_fast lhs, decimal64_fast rhs) noexcept -> dec } #endif - #if defined(__clang_major__) && __clang_major__ < 13 - - const auto result {detail::d64_mul_impl( - lhs.significand_, lhs.biased_exponent(), lhs.isneg(), - rhs.significand_, rhs.biased_exponent(), rhs.isneg() - )}; - - return {result.sig, result.exp, result.sign}; - - #else - #ifdef BOOST_DECIMAL_HAS_INT128 using unsigned_int128_type = boost::decimal::detail::uint128_t; #else @@ -1093,8 +1082,6 @@ constexpr auto operator*(decimal64_fast lhs, decimal64_fast rhs) noexcept -> dec bool sign {lhs.sign_ != rhs.sign_ && res_sig != 0}; return {res_sig, res_exp, sign}; - - #endif // Clang major check } template From 457cc1c95d0c0abae4421f12ce5ebe56cd8305ed Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 24 Jun 2024 16:24:08 -0400 Subject: [PATCH 31/45] Simplify value of sign --- include/boost/decimal/detail/mul_impl.hpp | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/include/boost/decimal/detail/mul_impl.hpp b/include/boost/decimal/detail/mul_impl.hpp index 008b17bfc..c7b8cbb36 100644 --- a/include/boost/decimal/detail/mul_impl.hpp +++ b/include/boost/decimal/detail/mul_impl.hpp @@ -30,16 +30,10 @@ BOOST_DECIMAL_FORCE_INLINE constexpr auto mul_impl(T lhs_sig, U lhs_exp, bool lh { using mul_type = std::uint_fast64_t; - bool sign {lhs_sign != rhs_sign}; auto res_sig {static_cast(lhs_sig) * static_cast(rhs_sig)}; auto res_exp {lhs_exp + rhs_exp}; - if (res_sig == 0) - { - sign = false; - } - - return {res_sig, res_exp, sign}; + return {res_sig, res_exp, lhs_sign != rhs_sign && res_sig != 0}; } template @@ -99,20 +93,13 @@ BOOST_DECIMAL_FORCE_INLINE constexpr auto d64_mul_impl(T lhs_sig, U lhs_exp, boo using unsigned_int128_type = boost::decimal::detail::uint128; #endif - bool sign {lhs_sign != rhs_sign}; - // Once we have the normalized significands and exponents all we have to do is // multiply the significands and add the exponents auto res_sig {static_cast(lhs_sig) * static_cast(rhs_sig)}; auto res_exp {lhs_exp + rhs_exp}; - if (res_sig == 0) - { - sign = false; - } - - return {res_sig, res_exp, sign}; + return {res_sig, res_exp, lhs_sign != rhs_sign && res_sig != 0}; } template From de73cbc87921d72cae9ef8057b558cca50142b22 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 25 Jun 2024 07:12:06 -0400 Subject: [PATCH 32/45] Fix narrowing conversions --- include/boost/decimal/detail/add_impl.hpp | 12 ++++++------ include/boost/decimal/detail/cmath/frexp10.hpp | 2 +- include/boost/decimal/detail/comparison.hpp | 8 ++++++-- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/include/boost/decimal/detail/add_impl.hpp b/include/boost/decimal/detail/add_impl.hpp index 9940ae8ce..ba65038b1 100644 --- a/include/boost/decimal/detail/add_impl.hpp +++ b/include/boost/decimal/detail/add_impl.hpp @@ -17,9 +17,9 @@ namespace boost { namespace decimal { namespace detail { -template -BOOST_DECIMAL_FORCE_INLINE constexpr auto add_impl(T1 lhs_sig, std::int32_t lhs_exp, bool lhs_sign, - T2 rhs_sig, std::int32_t rhs_exp, bool rhs_sign) noexcept -> ReturnType +template +BOOST_DECIMAL_FORCE_INLINE constexpr auto add_impl(T lhs_sig, U lhs_exp, bool lhs_sign, + T rhs_sig, U rhs_exp, bool rhs_sign) noexcept -> ReturnType { const bool sign {lhs_sign}; @@ -90,9 +90,9 @@ BOOST_DECIMAL_FORCE_INLINE constexpr auto add_impl(T1 lhs_sig, std::int32_t lhs_ return {new_sig, new_exp, sign}; } -template -constexpr auto d64_add_impl(T1 lhs_sig, std::int32_t lhs_exp, bool lhs_sign, - T2 rhs_sig, std::int32_t rhs_exp, bool rhs_sign) noexcept -> ReturnType +template +constexpr auto d64_add_impl(T lhs_sig, U lhs_exp, bool lhs_sign, + T rhs_sig, U rhs_exp, bool rhs_sign) noexcept -> ReturnType { const bool sign {lhs_sign}; diff --git a/include/boost/decimal/detail/cmath/frexp10.hpp b/include/boost/decimal/detail/cmath/frexp10.hpp index 85f7f4468..5bc5e9fa3 100644 --- a/include/boost/decimal/detail/cmath/frexp10.hpp +++ b/include/boost/decimal/detail/cmath/frexp10.hpp @@ -47,7 +47,7 @@ constexpr auto frexp10(T num, int* expptr) noexcept -> typename T::significand_t auto num_sig {num.full_significand()}; detail::normalize(num_sig, num_exp); - *expptr = num_exp; + *expptr = static_cast(num_exp); return num_sig; } diff --git a/include/boost/decimal/detail/comparison.hpp b/include/boost/decimal/detail/comparison.hpp index 2c75c99ef..7ca0acca6 100644 --- a/include/boost/decimal/detail/comparison.hpp +++ b/include/boost/decimal/detail/comparison.hpp @@ -55,6 +55,8 @@ template std::enable_if_t<(detail::is_decimal_floating_point_v && detail::is_integral_v), bool> { + using exp_type = typename Decimal::biased_exponent_type; + if (isnan(lhs) || isinf(lhs)) { return false; @@ -72,7 +74,7 @@ constexpr auto mixed_equality_impl(Decimal lhs, Integer rhs) noexcept const auto rhs_significand {detail::make_positive_unsigned(rhs)}; return equal_parts_impl(lhs.full_significand(), lhs.biased_exponent(), lhs.isneg(), - rhs_significand, INT32_C(0), rhs_isneg); + rhs_significand, static_cast(0), rhs_isneg); } template @@ -151,6 +153,8 @@ template std::enable_if_t<(detail::is_decimal_floating_point_v && detail::is_integral_v), bool> { + using exp_type = typename Decimal::biased_exponent_type; + if (isnan(lhs)) { return false; @@ -190,7 +194,7 @@ constexpr auto less_impl(Decimal lhs, Integer rhs) noexcept const auto rhs_significand {detail::make_positive_unsigned(rhs)}; return less_parts_impl(lhs.full_significand(), lhs.biased_exponent(), lhs_sign, - rhs_significand, INT32_C(0), rhs_sign); + rhs_significand, static_cast(0), rhs_sign); } template From adc665740ab5d3fc7b8b2ead9be4560736909de7 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 25 Jun 2024 07:27:56 -0400 Subject: [PATCH 33/45] Add typedefs to 128 bit types --- include/boost/decimal/decimal128.hpp | 9 ++++++--- include/boost/decimal/decimal128_fast.hpp | 12 +++++++----- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/include/boost/decimal/decimal128.hpp b/include/boost/decimal/decimal128.hpp index aab6380a9..d45947992 100644 --- a/include/boost/decimal/decimal128.hpp +++ b/include/boost/decimal/decimal128.hpp @@ -132,10 +132,11 @@ BOOST_DECIMAL_CONSTEXPR_VARIABLE uint128 d128_big_combination_field_mask {UINT64 struct decimal128_components { - using sig_type = uint128; + using significand_type = uint128; + using biased_exponent_type = std::int32_t; - uint128 sig {}; - std::int32_t exp {}; + significand_type sig {}; + biased_exponent_type exp {}; bool sign {}; constexpr decimal128_components() = default; @@ -150,6 +151,8 @@ BOOST_DECIMAL_EXPORT class decimal128 final { public: using significand_type = detail::uint128; + using exponent_type = std::uint64_t; + using biased_exponent_type = std::int32_t; private: detail::uint128 bits_ {}; diff --git a/include/boost/decimal/decimal128_fast.hpp b/include/boost/decimal/decimal128_fast.hpp index c34c256fe..ec43d8597 100644 --- a/include/boost/decimal/decimal128_fast.hpp +++ b/include/boost/decimal/decimal128_fast.hpp @@ -31,10 +31,11 @@ BOOST_DECIMAL_CONSTEXPR_VARIABLE auto d128_fast_snan = std::numeric_limits std::int32_t + constexpr auto biased_exponent() const noexcept -> biased_exponent_type { - return static_cast(exponent_) - detail::bias_v; + return static_cast(exponent_) - detail::bias_v; } template From 0730545e92bf7d73e93fb9aeb4f96c7434f11bdb Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 25 Jun 2024 07:28:02 -0400 Subject: [PATCH 34/45] Fix more conversions --- include/boost/decimal/detail/add_impl.hpp | 12 ++++++------ include/boost/decimal/detail/comparison.hpp | 14 ++++++++------ include/boost/decimal/detail/mul_impl.hpp | 2 +- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/include/boost/decimal/detail/add_impl.hpp b/include/boost/decimal/detail/add_impl.hpp index ba65038b1..54628abc2 100644 --- a/include/boost/decimal/detail/add_impl.hpp +++ b/include/boost/decimal/detail/add_impl.hpp @@ -54,7 +54,7 @@ BOOST_DECIMAL_FORCE_INLINE constexpr auto add_impl(T lhs_sig, U lhs_exp, bool lh // 32-bit signed int can have 9 digits and our normalized significand has 7 if (delta_exp <= 2) { - lhs_sig *= pow10(static_cast(delta_exp)); + lhs_sig *= pow10(static_cast(delta_exp)); lhs_exp -= delta_exp; delta_exp = 0; } @@ -66,7 +66,7 @@ BOOST_DECIMAL_FORCE_INLINE constexpr auto add_impl(T lhs_sig, U lhs_exp, bool lh if (delta_exp > 1) { - rhs_sig /= pow10(static_cast(delta_exp - 1)); + rhs_sig /= pow10(static_cast(delta_exp - 1)); delta_exp = 1; } } @@ -131,7 +131,7 @@ constexpr auto d64_add_impl(T lhs_sig, U lhs_exp, bool lhs_sign, // 64-bit sign int can have 19 digits, and our normalized significand has 16 if (delta_exp <= 3) { - lhs_sig *= pow10(static_cast(delta_exp)); + lhs_sig *= pow10(static_cast(delta_exp)); lhs_exp -= delta_exp; delta_exp = 0; } @@ -143,7 +143,7 @@ constexpr auto d64_add_impl(T lhs_sig, U lhs_exp, bool lhs_sign, if (delta_exp > 1) { - rhs_sig /= pow10(static_cast(delta_exp - 1)); + rhs_sig /= pow10(static_cast(delta_exp - 1)); delta_exp = 1; } @@ -239,8 +239,8 @@ constexpr auto d128_add_impl(T1 lhs_sig, std::int32_t lhs_exp, bool lhs_sign, } } - const auto new_sig {static_cast(lhs_sig) + - static_cast(rhs_sig)}; + const auto new_sig {static_cast(lhs_sig) + + static_cast(rhs_sig)}; const auto new_exp {lhs_exp}; #ifdef BOOST_DECIMAL_DEBUG_ADD_128 diff --git a/include/boost/decimal/detail/comparison.hpp b/include/boost/decimal/detail/comparison.hpp index 7ca0acca6..096863a07 100644 --- a/include/boost/decimal/detail/comparison.hpp +++ b/include/boost/decimal/detail/comparison.hpp @@ -23,9 +23,10 @@ namespace boost { namespace decimal { -template -constexpr auto equal_parts_impl(T1 lhs_sig, std::int32_t lhs_exp, bool lhs_sign, - T2 rhs_sig, std::int32_t rhs_exp, bool rhs_sign) noexcept -> bool +template +constexpr auto equal_parts_impl(T1 lhs_sig, U1 lhs_exp, bool lhs_sign, + T2 rhs_sig, U2 rhs_exp, bool rhs_sign) noexcept -> bool { using comp_type = std::conditional_t<(std::numeric_limits::digits10 > std::numeric_limits::digits10), T1, T2>; @@ -112,9 +113,10 @@ constexpr auto operator!=(Decimal1 lhs, Decimal2 rhs) noexcept return !(mixed_decimal_equality_impl(lhs, rhs)); } -template -constexpr auto less_parts_impl(T1 lhs_sig, std::int32_t lhs_exp, bool lhs_sign, - T2 rhs_sig, std::int32_t rhs_exp, bool rhs_sign) noexcept -> bool +template +constexpr auto less_parts_impl(T1 lhs_sig, U1 lhs_exp, bool lhs_sign, + T2 rhs_sig, U2 rhs_exp, bool rhs_sign) noexcept -> bool { using comp_type = std::conditional_t<(std::numeric_limits::digits10 > std::numeric_limits::digits10), T1, T2>; diff --git a/include/boost/decimal/detail/mul_impl.hpp b/include/boost/decimal/detail/mul_impl.hpp index c7b8cbb36..e13b9c577 100644 --- a/include/boost/decimal/detail/mul_impl.hpp +++ b/include/boost/decimal/detail/mul_impl.hpp @@ -194,7 +194,7 @@ constexpr auto d128_fast_mul_impl(T1 lhs_sig, std::int32_t lhs_exp, bool lhs_sig constexpr auto comp_value {impl::emulated_256_pow10[67]}; const auto sig_dig {res_sig >= comp_value ? 68 : 67}; - constexpr auto max_dig {std::numeric_limits::digits10}; + constexpr auto max_dig {std::numeric_limits::digits10}; res_sig /= detail::pow10(static_cast(sig_dig - max_dig)); res_exp += sig_dig - max_dig; From cc5cff46e7b38aa3ca19d923d8f372a103008456 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 25 Jun 2024 07:39:11 -0400 Subject: [PATCH 35/45] Fix conversions in decima128_fast --- include/boost/decimal/decimal128_fast.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/boost/decimal/decimal128_fast.hpp b/include/boost/decimal/decimal128_fast.hpp index ec43d8597..caa6e7ba5 100644 --- a/include/boost/decimal/decimal128_fast.hpp +++ b/include/boost/decimal/decimal128_fast.hpp @@ -822,7 +822,7 @@ constexpr auto operator+(decimal128_fast lhs, Integer rhs) noexcept auto lhs_components {detail::decimal128_fast_components{lhs.significand_, lhs.biased_exponent(), lhs.isneg()}}; auto sig_rhs {static_cast(detail::make_positive_unsigned(rhs))}; - std::int32_t exp_rhs {0}; + decimal128_fast::biased_exponent_type exp_rhs {0}; detail::normalize(sig_rhs, exp_rhs); auto unsigned_sig_rhs = detail::make_positive_unsigned(sig_rhs); auto rhs_components {detail::decimal128_fast_components{unsigned_sig_rhs, exp_rhs, (rhs < 0)}}; @@ -916,7 +916,7 @@ constexpr auto operator-(decimal128_fast lhs, Integer rhs) noexcept auto lhs_components {detail::decimal128_fast_components{lhs.significand_, lhs.biased_exponent(), lhs.isneg()}}; auto sig_rhs {static_cast(detail::make_positive_unsigned(rhs))}; - std::int32_t exp_rhs {0}; + decimal128_fast::biased_exponent_type exp_rhs {0}; detail::normalize(sig_rhs, exp_rhs); auto unsigned_sig_rhs {detail::make_positive_unsigned(sig_rhs)}; auto rhs_components {detail::decimal128_fast_components{unsigned_sig_rhs, exp_rhs, (rhs < 0)}}; @@ -948,7 +948,7 @@ constexpr auto operator-(Integer lhs, decimal128_fast rhs) noexcept const bool abs_lhs_bigger {detail::make_positive_unsigned(lhs) > abs(rhs)}; auto sig_lhs {static_cast(detail::make_positive_unsigned(lhs))}; - std::int32_t exp_lhs {0}; + decimal128_fast::biased_exponent_type exp_lhs {0}; detail::normalize(sig_lhs, exp_lhs); auto unsigned_sig_lhs {detail::make_positive_unsigned(sig_lhs)}; auto lhs_components {detail::decimal128_fast_components{unsigned_sig_lhs, exp_lhs, (lhs < 0)}}; @@ -994,7 +994,7 @@ constexpr auto operator*(decimal128_fast lhs, Integer rhs) noexcept #endif auto rhs_sig {static_cast(detail::make_positive_unsigned(rhs))}; - std::int32_t rhs_exp {0}; + decimal128_fast::biased_exponent_type rhs_exp {0}; detail::normalize(rhs_sig, rhs_exp); const auto result {detail::d128_fast_mul_impl( @@ -1130,7 +1130,7 @@ constexpr auto operator/(decimal128_fast lhs, Integer rhs) noexcept detail::decimal128_fast_components lhs_components {lhs.significand_, lhs.biased_exponent(), lhs.isneg()}; auto rhs_sig {detail::make_positive_unsigned(rhs)}; - std::int32_t rhs_exp {}; + decimal128_fast::biased_exponent_type rhs_exp {}; detail::decimal128_fast_components rhs_components {rhs_sig, rhs_exp, rhs < 0}; detail::decimal128_fast_components q_components {}; From d1b0087132cb355f38f48613a3146489ecac6465 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 25 Jun 2024 08:02:23 -0400 Subject: [PATCH 36/45] Add template type for exponent --- include/boost/decimal/detail/add_impl.hpp | 7 ++++--- include/boost/decimal/detail/mul_impl.hpp | 7 ++++--- include/boost/decimal/detail/sub_impl.hpp | 7 ++++--- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/include/boost/decimal/detail/add_impl.hpp b/include/boost/decimal/detail/add_impl.hpp index 54628abc2..bade4b0e5 100644 --- a/include/boost/decimal/detail/add_impl.hpp +++ b/include/boost/decimal/detail/add_impl.hpp @@ -172,9 +172,10 @@ constexpr auto d64_add_impl(T lhs_sig, U lhs_exp, bool lhs_sign, # pragma warning(disable: 4127) // If constexpr macro only works for C++17 and above #endif -template -constexpr auto d128_add_impl(T1 lhs_sig, std::int32_t lhs_exp, bool lhs_sign, - T2 rhs_sig, std::int32_t rhs_exp, bool rhs_sign) noexcept -> ReturnType +template +constexpr auto d128_add_impl(T1 lhs_sig, U1 lhs_exp, bool lhs_sign, + T2 rhs_sig, U2 rhs_exp, bool rhs_sign) noexcept -> ReturnType { const bool sign {lhs_sign}; diff --git a/include/boost/decimal/detail/mul_impl.hpp b/include/boost/decimal/detail/mul_impl.hpp index e13b9c577..5a022ff0e 100644 --- a/include/boost/decimal/detail/mul_impl.hpp +++ b/include/boost/decimal/detail/mul_impl.hpp @@ -180,9 +180,10 @@ constexpr auto d128_mul_impl(T1 lhs_sig, std::int32_t lhs_exp, bool lhs_sign, return {res_sig.low, res_exp, sign}; } -template -constexpr auto d128_fast_mul_impl(T1 lhs_sig, std::int32_t lhs_exp, bool lhs_sign, - T2 rhs_sig, std::int32_t rhs_exp, bool rhs_sign) noexcept -> ReturnType +template +constexpr auto d128_fast_mul_impl(T1 lhs_sig, U1 lhs_exp, bool lhs_sign, + T2 rhs_sig, U2 rhs_exp, bool rhs_sign) noexcept -> ReturnType { bool sign {lhs_sign != rhs_sign}; diff --git a/include/boost/decimal/detail/sub_impl.hpp b/include/boost/decimal/detail/sub_impl.hpp index ea8e19506..88515d2ae 100644 --- a/include/boost/decimal/detail/sub_impl.hpp +++ b/include/boost/decimal/detail/sub_impl.hpp @@ -152,9 +152,10 @@ constexpr auto d64_sub_impl(T lhs_sig, U lhs_exp, bool lhs_sign, return {res_sig, new_exp, new_sign}; } -template -constexpr auto d128_sub_impl(T1 lhs_sig, std::int32_t lhs_exp, bool lhs_sign, - T2 rhs_sig, std::int32_t rhs_exp, bool rhs_sign, +template +constexpr auto d128_sub_impl(T1 lhs_sig, U1 lhs_exp, bool lhs_sign, + T2 rhs_sig, U2 rhs_exp, bool rhs_sign, bool abs_lhs_bigger) noexcept -> ReturnType { auto delta_exp {lhs_exp > rhs_exp ? lhs_exp - rhs_exp : rhs_exp - lhs_exp}; From 016d1d820d8ac90f724df5d83a265023b93738ad Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 25 Jun 2024 08:53:19 -0400 Subject: [PATCH 37/45] Add single division to keep from digit counting a uint128 --- include/boost/decimal/detail/mul_impl.hpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/include/boost/decimal/detail/mul_impl.hpp b/include/boost/decimal/detail/mul_impl.hpp index 5a022ff0e..280609c89 100644 --- a/include/boost/decimal/detail/mul_impl.hpp +++ b/include/boost/decimal/detail/mul_impl.hpp @@ -95,11 +95,17 @@ BOOST_DECIMAL_FORCE_INLINE constexpr auto d64_mul_impl(T lhs_sig, U lhs_exp, boo // Once we have the normalized significands and exponents all we have to do is // multiply the significands and add the exponents + // + // The constructor needs to calculate the number of digits in the significand which for uint128 is slow + // Since we know the value of res_sig is constrained to [(10^16)^2, (10^17 - 1)^2] which equates to + // either 31 or 32 decimal digits we can use a single division to make binary search occur with + // uint_fast64_t instead. 32 - 13 = 19 or 31 - 13 = 18 which are both still greater than + // digits10 + 1 for rounding which is 17 decimal digits - auto res_sig {static_cast(lhs_sig) * static_cast(rhs_sig)}; - auto res_exp {lhs_exp + rhs_exp}; + auto res_sig {(static_cast(lhs_sig) * static_cast(rhs_sig)) / pow10(static_cast(13))}; + auto res_exp {lhs_exp + rhs_exp + static_cast(13)}; - return {res_sig, res_exp, lhs_sign != rhs_sign && res_sig != 0}; + return {static_cast(res_sig), res_exp, lhs_sign != rhs_sign && res_sig != 0}; } template From a8f3259623c7b1d1db12eeb1e4ebc52798bf524d Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 25 Jun 2024 09:14:17 -0400 Subject: [PATCH 38/45] Speed up mul_impl for decimal32 and add additional impl for dec32_fast --- include/boost/decimal/detail/mul_impl.hpp | 26 +++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/include/boost/decimal/detail/mul_impl.hpp b/include/boost/decimal/detail/mul_impl.hpp index 280609c89..fabd4df81 100644 --- a/include/boost/decimal/detail/mul_impl.hpp +++ b/include/boost/decimal/detail/mul_impl.hpp @@ -26,14 +26,32 @@ namespace detail { template BOOST_DECIMAL_FORCE_INLINE constexpr auto mul_impl(T lhs_sig, U lhs_exp, bool lhs_sign, - T rhs_sig, U rhs_exp, bool rhs_sign) noexcept -> std::enable_if_t, ReturnType> + T rhs_sig, U rhs_exp, bool rhs_sign) noexcept -> std::enable_if_t::value, ReturnType> { using mul_type = std::uint_fast64_t; - auto res_sig {static_cast(lhs_sig) * static_cast(rhs_sig)}; - auto res_exp {lhs_exp + rhs_exp}; + const auto res_sig {static_cast(lhs_sig) * static_cast(rhs_sig)}; + const auto res_exp {lhs_exp + rhs_exp}; + + return {res_sig, res_exp, lhs_sign != rhs_sign && res_sig != static_cast(0)}; +} + +template +BOOST_DECIMAL_FORCE_INLINE constexpr auto mul_impl(T lhs_sig, U lhs_exp, bool lhs_sign, + T rhs_sig, U rhs_exp, bool rhs_sign) noexcept -> std::enable_if_t::value, ReturnType> +{ + using mul_type = std::uint_fast64_t; + + // The constructor needs to calculate the number of digits in the significand which for uint128 is slow + // Since we know the value of res_sig is constrained to [1'000'000^2, 9'999'999^2] which equates to + // either 13 or 14 decimal digits we can use a single division to make binary search occur with + // uint32_t instead. 14 - 5 = 9 or 13 - 5 = 8 which are both still greater than or equal to + // digits10 + 1 for rounding which is 8 decimal digits + + auto res_sig {(static_cast(lhs_sig) * static_cast(rhs_sig)) / pow10(static_cast(5))}; + auto res_exp {lhs_exp + rhs_exp + static_cast(5)}; - return {res_sig, res_exp, lhs_sign != rhs_sign && res_sig != 0}; + return {static_cast(res_sig), res_exp, lhs_sign != rhs_sign && res_sig != static_cast(0)}; } template From 3ca6e64bdd7b3faf6796e2d87ca425956eaefe28 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 25 Jun 2024 09:45:35 -0400 Subject: [PATCH 39/45] Change intermediate mul type for clang 6-12 --- include/boost/decimal/detail/mul_impl.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/boost/decimal/detail/mul_impl.hpp b/include/boost/decimal/detail/mul_impl.hpp index fabd4df81..ebd30ccd3 100644 --- a/include/boost/decimal/detail/mul_impl.hpp +++ b/include/boost/decimal/detail/mul_impl.hpp @@ -105,7 +105,8 @@ BOOST_DECIMAL_FORCE_INLINE constexpr auto d64_mul_impl(T lhs_sig, U lhs_exp, boo T rhs_sig, U rhs_exp, bool rhs_sign) noexcept -> std::enable_if_t, ReturnType> { - #ifdef BOOST_DECIMAL_HAS_INT128 + // Clang 6-12 yields incorrect results with builtin u128, so we force usage of our version + #if defined(BOOST_DECIMAL_HAS_INT128) && (!defined(__clang_major__) || (__clang_major__) > 12) using unsigned_int128_type = boost::decimal::detail::uint128_t; #else using unsigned_int128_type = boost::decimal::detail::uint128; From 7255a0a30fcae76a9b14a4e0751bb439f492bb0e Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 25 Jun 2024 11:39:11 -0400 Subject: [PATCH 40/45] Additional old clang workaround --- include/boost/decimal/decimal64_fast.hpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/include/boost/decimal/decimal64_fast.hpp b/include/boost/decimal/decimal64_fast.hpp index c58c8b474..47029698f 100644 --- a/include/boost/decimal/decimal64_fast.hpp +++ b/include/boost/decimal/decimal64_fast.hpp @@ -1070,6 +1070,18 @@ constexpr auto operator*(decimal64_fast lhs, decimal64_fast rhs) noexcept -> dec } #endif + + #if defined(__clang_major__) && __clang_major__ < 13 + + const auto result {detail::d64_mul_impl( + lhs.significand_, lhs.biased_exponent(), lhs.isneg(), + rhs.significand_, rhs.biased_exponent(), rhs.isneg() + )}; + + return {result.sig, result.exp, result.sign}; + + #else + #ifdef BOOST_DECIMAL_HAS_INT128 using unsigned_int128_type = boost::decimal::detail::uint128_t; #else @@ -1082,6 +1094,8 @@ constexpr auto operator*(decimal64_fast lhs, decimal64_fast rhs) noexcept -> dec bool sign {lhs.sign_ != rhs.sign_ && res_sig != 0}; return {res_sig, res_exp, sign}; + + #endif } template From 2616fdd049c52f4c4608f3fb301c261b4514a22e Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 25 Jun 2024 14:14:53 -0400 Subject: [PATCH 41/45] Fix handling of signed 0 --- include/boost/decimal/decimal64_fast.hpp | 2 +- include/boost/decimal/detail/mul_impl.hpp | 27 +++-------------------- test/random_decimal128_math.cpp | 12 ++++++++++ test/random_decimal32_fast_math.cpp | 12 ++++++++++ test/random_decimal32_math.cpp | 12 ++++++++++ test/random_decimal64_fast_math.cpp | 12 ++++++++++ test/random_decimal64_math.cpp | 12 ++++++++++ 7 files changed, 64 insertions(+), 25 deletions(-) diff --git a/include/boost/decimal/decimal64_fast.hpp b/include/boost/decimal/decimal64_fast.hpp index 47029698f..151c1e2d0 100644 --- a/include/boost/decimal/decimal64_fast.hpp +++ b/include/boost/decimal/decimal64_fast.hpp @@ -1091,7 +1091,7 @@ constexpr auto operator*(decimal64_fast lhs, decimal64_fast rhs) noexcept -> dec auto res_sig {static_cast(lhs.significand_) * static_cast(rhs.significand_)}; auto res_exp {lhs.biased_exponent() + rhs.biased_exponent()}; - bool sign {lhs.sign_ != rhs.sign_ && res_sig != 0}; + bool sign {lhs.sign_ != rhs.sign_}; return {res_sig, res_exp, sign}; diff --git a/include/boost/decimal/detail/mul_impl.hpp b/include/boost/decimal/detail/mul_impl.hpp index ebd30ccd3..d2b2e8845 100644 --- a/include/boost/decimal/detail/mul_impl.hpp +++ b/include/boost/decimal/detail/mul_impl.hpp @@ -33,7 +33,7 @@ BOOST_DECIMAL_FORCE_INLINE constexpr auto mul_impl(T lhs_sig, U lhs_exp, bool lh const auto res_sig {static_cast(lhs_sig) * static_cast(rhs_sig)}; const auto res_exp {lhs_exp + rhs_exp}; - return {res_sig, res_exp, lhs_sign != rhs_sign && res_sig != static_cast(0)}; + return {res_sig, res_exp, lhs_sign != rhs_sign}; } template @@ -51,7 +51,7 @@ BOOST_DECIMAL_FORCE_INLINE constexpr auto mul_impl(T lhs_sig, U lhs_exp, bool lh auto res_sig {(static_cast(lhs_sig) * static_cast(rhs_sig)) / pow10(static_cast(5))}; auto res_exp {lhs_exp + rhs_exp + static_cast(5)}; - return {static_cast(res_sig), res_exp, lhs_sign != rhs_sign && res_sig != static_cast(0)}; + return {static_cast(res_sig), res_exp, lhs_sign != rhs_sign}; } template @@ -92,11 +92,6 @@ BOOST_DECIMAL_FORCE_INLINE constexpr auto mul_impl(T lhs_sig, U lhs_exp, bool lh << "\nres exp: " << res_exp << std::endl; #endif - if (res_sig_32 == 0) - { - sign = false; - } - return {res_sig_32, res_exp, sign}; } @@ -124,7 +119,7 @@ BOOST_DECIMAL_FORCE_INLINE constexpr auto d64_mul_impl(T lhs_sig, U lhs_exp, boo auto res_sig {(static_cast(lhs_sig) * static_cast(rhs_sig)) / pow10(static_cast(13))}; auto res_exp {lhs_exp + rhs_exp + static_cast(13)}; - return {static_cast(res_sig), res_exp, lhs_sign != rhs_sign && res_sig != 0}; + return {static_cast(res_sig), res_exp, lhs_sign != rhs_sign}; } template @@ -167,12 +162,6 @@ BOOST_DECIMAL_FORCE_INLINE constexpr auto d64_mul_impl(T lhs_sig, U lhs_exp, boo << "\nres exp: " << res_exp << std::endl; #endif - // Always return positive zero - if (res_sig_64 == 0) - { - sign = false; - } - return {res_sig_64, res_exp, sign}; } @@ -196,11 +185,6 @@ constexpr auto d128_mul_impl(T1 lhs_sig, std::int32_t lhs_exp, bool lhs_sign, res_exp += digit_delta; } - if (res_sig == 0) - { - sign = false; - } - BOOST_DECIMAL_ASSERT(res_sig.high == uint128(0,0)); return {res_sig.low, res_exp, sign}; } @@ -224,11 +208,6 @@ constexpr auto d128_fast_mul_impl(T1 lhs_sig, U1 lhs_exp, bool lhs_sign, res_sig /= detail::pow10(static_cast(sig_dig - max_dig)); res_exp += sig_dig - max_dig; - if (res_sig == 0) - { - sign = false; - } - BOOST_DECIMAL_ASSERT(res_sig.high == uint128(0,0)); return {res_sig.low, res_exp, sign}; } diff --git a/test/random_decimal128_math.cpp b/test/random_decimal128_math.cpp index 9c3e47a0f..29d459768 100644 --- a/test/random_decimal128_math.cpp +++ b/test/random_decimal128_math.cpp @@ -249,6 +249,12 @@ void random_multiplication(T lower, T upper) const decimal128 res = dec1 * dec2; const auto res_int = static_cast(res); + if (val1 * val2 == 0) + { + // Integers don't have signed 0 but decimal does + continue; + } + if (!BOOST_TEST_EQ(res_int, val1 * val2)) { // LCOV_EXCL_START @@ -286,6 +292,12 @@ void random_mixed_multiplication(T lower, T upper) const decimal128 res {dec1 * dec2}; const T res_int {static_cast(res)}; + if (val1 * val2 == 0) + { + // Integers don't have signed 0 but decimal does + continue; + } + if (!BOOST_TEST_EQ(res_int, val1 * val2)) { // LCOV_EXCL_START diff --git a/test/random_decimal32_fast_math.cpp b/test/random_decimal32_fast_math.cpp index ff20d9241..6d959dcd4 100644 --- a/test/random_decimal32_fast_math.cpp +++ b/test/random_decimal32_fast_math.cpp @@ -249,6 +249,12 @@ void random_multiplication(T lower, T upper) const decimal32_fast res {dec1 * dec2}; const decimal32_fast res_int {val1 * val2}; + if (val1 * val2 == 0) + { + // Integers don't have signed 0 but decimal does + continue; + } + if (!BOOST_TEST_EQ(res, res_int)) { // LCOV_EXCL_START @@ -284,6 +290,12 @@ void random_mixed_multiplication(T lower, T upper) const decimal32_fast res {dec1 * dec2}; const decimal32_fast res_int {val1 * val2}; + if (val1 * val2 == 0) + { + // Integers don't have signed 0 but decimal does + continue; + } + if (!BOOST_TEST_EQ(res, res_int)) { // LCOV_EXCL_START diff --git a/test/random_decimal32_math.cpp b/test/random_decimal32_math.cpp index c17d78b18..6306ed665 100644 --- a/test/random_decimal32_math.cpp +++ b/test/random_decimal32_math.cpp @@ -249,6 +249,12 @@ void random_multiplication(T lower, T upper) const decimal32 res {dec1 * dec2}; const decimal32 res_int {val1 * val2}; + if (val1 * val2 == 0) + { + // Integers don't have signed 0 but decimal does + continue; + } + if (!BOOST_TEST_EQ(res, res_int)) { // LCOV_EXCL_START @@ -284,6 +290,12 @@ void random_mixed_multiplication(T lower, T upper) const decimal32 res {dec1 * dec2}; const decimal32 res_int {val1 * val2}; + if (val1 * val2 == 0) + { + // Integers don't have signed 0 but decimal does + continue; + } + if (!BOOST_TEST_EQ(res, res_int)) { // LCOV_EXCL_START diff --git a/test/random_decimal64_fast_math.cpp b/test/random_decimal64_fast_math.cpp index b8f5e6e32..3ac32a537 100644 --- a/test/random_decimal64_fast_math.cpp +++ b/test/random_decimal64_fast_math.cpp @@ -240,6 +240,12 @@ void random_multiplication(T lower, T upper) const decimal64_fast res {dec1 * dec2}; const decimal64_fast res_int {val1 * val2}; + if (val1 * val2 == 0) + { + // Integers don't have signed 0 but decimal does + continue; + } + if (!BOOST_TEST_EQ(res, res_int)) { // LCOV_EXCL_START @@ -275,6 +281,12 @@ void random_mixed_multiplication(T lower, T upper) const decimal64_fast res {dec1 * dec2}; const decimal64_fast res_int {val1 * val2}; + if (val1 * val2 == 0) + { + // Integers don't have signed 0 but decimal does + continue; + } + if (!BOOST_TEST_EQ(res, res_int)) { // LCOV_EXCL_START diff --git a/test/random_decimal64_math.cpp b/test/random_decimal64_math.cpp index 36e0400d9..2b5839c53 100644 --- a/test/random_decimal64_math.cpp +++ b/test/random_decimal64_math.cpp @@ -239,6 +239,12 @@ void random_multiplication(T lower, T upper) const decimal64 res {dec1 * dec2}; const decimal64 res_int {val1 * val2}; + if (val1 * val2 == 0) + { + // Integers don't have signed 0 but decimal does + continue; + } + if (!BOOST_TEST_EQ(res, res_int)) { // LCOV_EXCL_START @@ -274,6 +280,12 @@ void random_mixed_multiplication(T lower, T upper) const decimal64 res {dec1 * dec2}; const decimal64 res_int {val1 * val2}; + if (val1 * val2 == 0) + { + // Integers don't have signed 0 but decimal does + continue; + } + if (!BOOST_TEST_EQ(res, res_int)) { // LCOV_EXCL_START From b7163d8c492741099e19d475a037cb49189cfb48 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 25 Jun 2024 14:44:58 -0400 Subject: [PATCH 42/45] Fix testing of signed 0s --- test/test_cmath.cpp | 6 +++--- test/test_decimal32.cpp | 2 +- test/test_decimal32_fast_basis.cpp | 2 +- test/test_decimal64_fast_basis.cpp | 2 +- test/test_sin_cos.cpp | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/test/test_cmath.cpp b/test/test_cmath.cpp index 3305c074b..dada43200 100644 --- a/test/test_cmath.cpp +++ b/test/test_cmath.cpp @@ -778,7 +778,7 @@ void test_rint() BOOST_TEST(isinf(rint(std::numeric_limits::infinity() * Dec(dist(rng))))); BOOST_TEST(isnan(rint(std::numeric_limits::quiet_NaN() * Dec(dist(rng))))); - BOOST_TEST_EQ(rint(Dec(0) * Dec(dist(rng))), Dec(0)); + BOOST_TEST_EQ(abs(rint(Dec(0) * Dec(dist(rng)))), Dec(0)); BOOST_TEST_EQ(rint(Dec(0) * Dec(dist(rng)) + Dec(1, -20)), Dec(0)); BOOST_TEST_EQ(rint(Dec(0) * Dec(dist(rng)) + Dec(1, -20, true)), Dec(0, 0, true)); } @@ -966,7 +966,7 @@ void test_nearbyint() BOOST_TEST(isinf(nearbyint(std::numeric_limits::infinity() * Dec(dist(rng))))); BOOST_TEST(isnan(nearbyint(std::numeric_limits::quiet_NaN() * Dec(dist(rng))))); - BOOST_TEST_EQ(nearbyint(Dec(0) * Dec(dist(rng))), Dec(0)); + BOOST_TEST_EQ(abs(nearbyint(Dec(0) * Dec(dist(rng)))), Dec(0)); BOOST_TEST_EQ(nearbyint(Dec(0) * Dec(dist(rng)) + Dec(1, -20)), Dec(0)); BOOST_TEST_EQ(nearbyint(Dec(0) * Dec(dist(rng)) + Dec(1, -20, true)), Dec(0, 0, true)); } @@ -1008,7 +1008,7 @@ void test_round() BOOST_TEST(isinf(round(std::numeric_limits::infinity() * Dec(dist(rng))))); BOOST_TEST(isnan(round(std::numeric_limits::quiet_NaN() * Dec(dist(rng))))); - BOOST_TEST_EQ(round(Dec(0) * Dec(dist(rng))), Dec(0)); + BOOST_TEST_EQ(abs(round(Dec(0) * Dec(dist(rng)))), Dec(0)); BOOST_TEST_EQ(round(Dec(0) * Dec(dist(rng)) + Dec(1, -20)), Dec(0)); BOOST_TEST_EQ(round(Dec(0) * Dec(dist(rng)) + Dec(1, -20, true)), Dec(0, 0, false)); } diff --git a/test/test_decimal32.cpp b/test/test_decimal32.cpp index 23060d3c2..3b543175e 100644 --- a/test/test_decimal32.cpp +++ b/test/test_decimal32.cpp @@ -345,7 +345,7 @@ void test_multiplicatiom() constexpr decimal32 eight {8, 0}; BOOST_TEST_EQ(zero * one, zero); - BOOST_TEST_EQ(zero * -one, zero); + BOOST_TEST_EQ(zero * -one, -zero); BOOST_TEST_EQ(one * two, two); decimal32 pow_two {1, 0}; diff --git a/test/test_decimal32_fast_basis.cpp b/test/test_decimal32_fast_basis.cpp index 33fcff601..031461293 100644 --- a/test/test_decimal32_fast_basis.cpp +++ b/test/test_decimal32_fast_basis.cpp @@ -290,7 +290,7 @@ void test_multiplicatiom() constexpr decimal32_fast eight {8, 0}; BOOST_TEST_EQ(zero * one, zero); - BOOST_TEST_EQ(zero * -one, zero); + BOOST_TEST_EQ(zero * -one, -zero); BOOST_TEST_EQ(one * two, two); decimal32_fast pow_two {1, 0}; diff --git a/test/test_decimal64_fast_basis.cpp b/test/test_decimal64_fast_basis.cpp index 1306ad1b4..b1b67fccc 100644 --- a/test/test_decimal64_fast_basis.cpp +++ b/test/test_decimal64_fast_basis.cpp @@ -269,7 +269,7 @@ void test_multiplicatiom() constexpr decimal64_fast eight {8, 0}; BOOST_TEST_EQ(zero * one, zero); - BOOST_TEST_EQ(zero * -one, zero); + BOOST_TEST_EQ(zero * -one, -zero); BOOST_TEST_EQ(one * two, two); decimal64_fast pow_two {1, 0}; diff --git a/test/test_sin_cos.cpp b/test/test_sin_cos.cpp index 4edc1f489..6880415ec 100644 --- a/test/test_sin_cos.cpp +++ b/test/test_sin_cos.cpp @@ -68,7 +68,7 @@ void test_sin() BOOST_TEST(isinf(sin(std::numeric_limits::infinity() * Dec(dist(rng))))); BOOST_TEST(isnan(sin(std::numeric_limits::quiet_NaN() * Dec(dist(rng))))); - BOOST_TEST_EQ(sin(Dec(0) * Dec(dist(rng))), Dec(0)); + BOOST_TEST_EQ(abs(sin(Dec(0) * Dec(dist(rng)))), Dec(0)); // Check the phases of large positive/negative arguments. using std::atan; From 49631b185a51e76c64142e7872cc521c3fb5a4b3 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 25 Jun 2024 14:57:10 -0400 Subject: [PATCH 43/45] Fix type of exp --- include/boost/decimal/detail/mul_impl.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/decimal/detail/mul_impl.hpp b/include/boost/decimal/detail/mul_impl.hpp index d2b2e8845..f5d56d4a5 100644 --- a/include/boost/decimal/detail/mul_impl.hpp +++ b/include/boost/decimal/detail/mul_impl.hpp @@ -148,7 +148,7 @@ BOOST_DECIMAL_FORCE_INLINE constexpr auto d64_mul_impl(T lhs_sig, U lhs_exp, boo // multiply the significands and add the exponents auto res_sig {static_cast(lhs_sig) * static_cast(rhs_sig)}; - auto res_exp {lhs_exp + rhs_exp}; + auto res_exp {static_cast(lhs_exp + rhs_exp)}; const auto sig_dig {res_sig >= comp_value ? 32 : 31}; constexpr auto max_dig {std::numeric_limits::digits10}; From cdf9ffa65a2a8e9e9167bc66359d87a361b2592d Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 25 Jun 2024 16:18:20 -0400 Subject: [PATCH 44/45] Further clang workarounds --- include/boost/decimal/detail/mul_impl.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/decimal/detail/mul_impl.hpp b/include/boost/decimal/detail/mul_impl.hpp index f5d56d4a5..29855414e 100644 --- a/include/boost/decimal/detail/mul_impl.hpp +++ b/include/boost/decimal/detail/mul_impl.hpp @@ -127,7 +127,7 @@ BOOST_DECIMAL_FORCE_INLINE constexpr auto d64_mul_impl(T lhs_sig, U lhs_exp, boo T rhs_sig, U rhs_exp, bool rhs_sign) noexcept -> std::enable_if_t, ReturnType> { - #ifdef BOOST_DECIMAL_HAS_INT128 + #if defined(BOOST_DECIMAL_HAS_INT128) && (!defined(__clang_major__) || __clang_major__ > 13) using unsigned_int128_type = boost::decimal::detail::uint128_t; constexpr auto comp_value {impl::builtin_128_pow10[31]}; #else From f6fa637739fb606fdb0ab773696ac27537454f63 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 26 Jun 2024 07:38:09 -0400 Subject: [PATCH 45/45] Change division type for old clangs --- include/boost/decimal/decimal64_fast.hpp | 16 ++++++++++++---- include/boost/decimal/detail/div_impl.hpp | 2 +- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/include/boost/decimal/decimal64_fast.hpp b/include/boost/decimal/decimal64_fast.hpp index 151c1e2d0..de90dc71b 100644 --- a/include/boost/decimal/decimal64_fast.hpp +++ b/include/boost/decimal/decimal64_fast.hpp @@ -1227,6 +1227,9 @@ template constexpr auto operator/(decimal64_fast lhs, Integer rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal64_fast) { + using promoted_significand_type = detail::promote_significand_t; + using exp_type = detail::decimal64_fast_components::biased_exponent_type; + #ifndef BOOST_DECIMAL_FAST_MATH // Check pre-conditions constexpr decimal64_fast zero {0, 0}; @@ -1261,8 +1264,8 @@ constexpr auto operator/(decimal64_fast lhs, Integer rhs) noexcept detail::decimal64_fast_components lhs_components {lhs_sig, lhs_exp, lhs.isneg()}; - auto rhs_sig {static_cast(detail::make_positive_unsigned(rhs))}; - std::int32_t rhs_exp {}; + auto rhs_sig {static_cast(detail::make_positive_unsigned(rhs))}; + exp_type rhs_exp {}; detail::decimal64_fast_components rhs_components {detail::shrink_significand(rhs_sig, rhs_exp), rhs_exp, rhs < 0}; return detail::d64_generic_div_impl(lhs_components, rhs_components); @@ -1272,6 +1275,9 @@ template constexpr auto operator/(Integer lhs, decimal64_fast rhs) noexcept BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal64_fast) { + using promoted_significand_type = detail::promote_significand_t; + using exp_type = detail::decimal64_fast_components::biased_exponent_type; + #ifndef BOOST_DECIMAL_FAST_MATH // Check pre-conditions constexpr decimal64_fast zero {0, 0}; @@ -1301,10 +1307,12 @@ constexpr auto operator/(Integer lhs, decimal64_fast rhs) noexcept auto rhs_sig {rhs.full_significand()}; auto rhs_exp {rhs.biased_exponent()}; detail::normalize(rhs_sig, rhs_exp); - - detail::decimal64_fast_components lhs_components {detail::make_positive_unsigned(lhs), 0, lhs < 0}; detail::decimal64_fast_components rhs_components {rhs_sig, rhs_exp, rhs.isneg()}; + auto lhs_sig {static_cast(detail::make_positive_unsigned(lhs))}; + exp_type lhs_exp {}; + detail::decimal64_fast_components lhs_components {detail::shrink_significand(lhs_sig, lhs_exp), lhs_exp, lhs < 0}; + return detail::d64_generic_div_impl(lhs_components, rhs_components); } diff --git a/include/boost/decimal/detail/div_impl.hpp b/include/boost/decimal/detail/div_impl.hpp index 46fa73099..5ee1405a4 100644 --- a/include/boost/decimal/detail/div_impl.hpp +++ b/include/boost/decimal/detail/div_impl.hpp @@ -45,7 +45,7 @@ BOOST_DECIMAL_FORCE_INLINE constexpr auto generic_div_impl(const T& lhs, const T template constexpr auto d64_generic_div_impl(const T& lhs, const T& rhs) noexcept -> DecimalType { - #ifdef BOOST_DECIMAL_HAS_INT128 + #if defined(BOOST_DECIMAL_HAS_INT128) && (!defined(__clang_major__) || __clang_major__ > 13) using unsigned_int128_type = boost::decimal::detail::uint128_t; #else using unsigned_int128_type = boost::decimal::detail::uint128;