diff --git a/include/boost/decimal/detail/mul_impl.hpp b/include/boost/decimal/detail/mul_impl.hpp index 6c0857673..7322109f0 100644 --- a/include/boost/decimal/detail/mul_impl.hpp +++ b/include/boost/decimal/detail/mul_impl.hpp @@ -500,7 +500,7 @@ BOOST_DECIMAL_CUDA_CONSTEXPR auto d128_mul_impl(const T1& lhs_sig_in, const U1 l auto res_sig {detail::umul256(lhs_sig_in, rhs_sig_in)}; auto res_exp_mut {static_cast(lhs_exp_in + rhs_exp_in)}; const auto sig_dig {detail::num_digits(res_sig)}; - const auto digit_delta {sig_dig - std::numeric_limits::digits10}; + const auto digit_delta {sig_dig - detail::precision_v}; if (BOOST_DECIMAL_LIKELY(digit_delta > 0)) { auto biased_exp {res_exp_mut + detail::bias_v}; diff --git a/test/Jamfile b/test/Jamfile index 8693a2bd9..9de4c0143 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -143,6 +143,7 @@ run github_issue_1459_toward_zero.cpp run github_issue_1467.cpp ; run github_issue_1473.cpp ; run github_issue_1476.cpp ; +run github_issue_1482.cpp ; run link_1.cpp link_2.cpp link_3.cpp ; run quick.cpp ; diff --git a/test/github_issue_1482.cpp b/test/github_issue_1482.cpp new file mode 100644 index 000000000..94612c887 --- /dev/null +++ b/test/github_issue_1482.cpp @@ -0,0 +1,54 @@ +// Copyright 2026 Shen-Ta Hsieh +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include + +using namespace boost::decimal; +using namespace boost::decimal::literals; + +// The exponents sum to below -6142, and the product of the short operands has 36 to 38 +// digits. The multiply must round it to 34 digits before it packs the result. +int main() +{ + BOOST_TEST_EQ(34e-6168_DL * 6304777571276319608815211782449451e-6_DL, 2143624374233948666997172006032813e-6172_DL); + BOOST_TEST_EQ(99e-6150_DL * 1234567890123456789012345678901234e-20_DL, 1222222211222222221122222222112222e-6168_DL); + BOOST_TEST_EQ(9999e-6160_DL * 9999999999999999999999999999999999e-10_DL, 9998999999999999999999999999999999e-6166_DL); + // A tie goes to the even neighbour + BOOST_TEST_EQ(5e-6160_DL * 2000000000000000000000000000000001e-10_DL, 1000000000000000000000000000000000e-6169_DL); + + // A 38-digit product far below the smallest subnormal rounds to zero + BOOST_TEST_EQ(9999999999999999999e-3112_DL * 9999999999999999999e-3113_DL, 0_DL); + + // fesetround has an effect only with the detection of constant evaluation + #ifndef BOOST_DECIMAL_NO_CONSTEVAL_DETECTION + // A positive product goes up, a negative product goes toward zero + fesetround(rounding_mode::fe_dec_upward); + BOOST_TEST_EQ(34e-6168_DL * 6304777571276319608815211782449451e-6_DL, 2143624374233948666997172006032814e-6172_DL); + BOOST_TEST_EQ(9999e-6160_DL * 9999999999999999999999999999999999e-10_DL, 9999000000000000000000000000000000e-6166_DL); + BOOST_TEST_EQ(-5e-6160_DL * 2000000000000000000000000000000001e-10_DL, -1000000000000000000000000000000000e-6169_DL); + + // A negative product goes down, a positive product goes toward zero + fesetround(rounding_mode::fe_dec_downward); + BOOST_TEST_EQ(-34e-6168_DL * 6304777571276319608815211782449451e-6_DL, -2143624374233948666997172006032814e-6172_DL); + BOOST_TEST_EQ(-9999e-6160_DL * 9999999999999999999999999999999999e-10_DL, -9999000000000000000000000000000000e-6166_DL); + BOOST_TEST_EQ(99e-6150_DL * 1234567890123456789012345678901234e-20_DL, 1222222211222222221122222222112221e-6168_DL); + + // A tie goes away from zero + fesetround(rounding_mode::fe_dec_to_nearest_from_zero); + BOOST_TEST_EQ(5e-6160_DL * 2000000000000000000000000000000001e-10_DL, 1000000000000000000000000000000001e-6169_DL); + BOOST_TEST_EQ(-5e-6160_DL * 2000000000000000000000000000000001e-10_DL, -1000000000000000000000000000000001e-6169_DL); + BOOST_TEST_EQ(99e-6150_DL * 1234567890123456789012345678901234e-20_DL, 1222222211222222221122222222112222e-6168_DL); + + // All products go toward zero + fesetround(rounding_mode::fe_dec_toward_zero); + BOOST_TEST_EQ(99e-6150_DL * 1234567890123456789012345678901234e-20_DL, 1222222211222222221122222222112221e-6168_DL); + BOOST_TEST_EQ(-9999e-6160_DL * 9999999999999999999999999999999999e-10_DL, -9998999999999999999999999999999999e-6166_DL); + BOOST_TEST_EQ(5e-6160_DL * 2000000000000000000000000000000001e-10_DL, 1000000000000000000000000000000000e-6169_DL); + + fesetround(rounding_mode::fe_dec_to_nearest); + #endif + + return boost::report_errors(); +}