From ad17c31714065a567a21135289b98fbb27f56e7c Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 21 Jan 2026 14:48:47 -0500 Subject: [PATCH 1/5] Add reproducer rounding error --- test/github_issue_1026.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/github_issue_1026.cpp b/test/github_issue_1026.cpp index 5a75afc42..94ee6badb 100644 --- a/test/github_issue_1026.cpp +++ b/test/github_issue_1026.cpp @@ -45,6 +45,8 @@ int main() BOOST_TEST_EQ("9999999999999999999999999992345678.49"_DL, "9999999999999999999999999992345678"_DL); BOOST_TEST_EQ("9999999999999999999999999992345678.50"_DL, "9999999999999999999999999992345678"_DL); BOOST_TEST_EQ("9999999999999999999999999992345678.51"_DL, "9999999999999999999999999992345679"_DL); + BOOST_TEST_EQ("145433.2908011933696719165119928295655062562131932287426051970822"_DL, "145433.2908011933696719165119928296"_DL); + BOOST_TEST_EQ("30269.587755640502150977251770554"_DL * "4.8046009735990873395936309640543"_DL, "145433.2908011933696719165119928296"_DL); BOOST_TEST_EQ(("0"_DF + "8.4e-96"_DF), "8.4e-96"_DF); BOOST_TEST_EQ(("0"_DF + std::numeric_limits::denorm_min()), std::numeric_limits::denorm_min()); From ec90aa6468b7606e7b83bd17c1decd30c84a5b51 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 21 Jan 2026 14:49:04 -0500 Subject: [PATCH 2/5] Increase number of digits saved for rounding in constructor --- 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 8d8b4d9be..575d8f0b0 100644 --- a/include/boost/decimal/detail/mul_impl.hpp +++ b/include/boost/decimal/detail/mul_impl.hpp @@ -162,7 +162,7 @@ constexpr auto d128_mul_impl(const T1& lhs_sig, const U1 lhs_exp, const bool lhs // 34 is the number of digits in the d128 significand // this way we can skip rounding in the constructor a second time - const auto digit_delta {sig_dig - 34}; + const auto digit_delta {sig_dig - std::numeric_limits::digits10}; if (BOOST_DECIMAL_LIKELY(digit_delta > 0)) { res_sig /= pow10(digit_delta); From deaeac9ca98c85c6dde64d33b06204f00c4c1dc4 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 21 Jan 2026 15:34:15 -0500 Subject: [PATCH 3/5] Round directly instead of chopping digits --- include/boost/decimal/detail/mul_impl.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/decimal/detail/mul_impl.hpp b/include/boost/decimal/detail/mul_impl.hpp index 575d8f0b0..a1f81a9ce 100644 --- a/include/boost/decimal/detail/mul_impl.hpp +++ b/include/boost/decimal/detail/mul_impl.hpp @@ -165,8 +165,8 @@ constexpr auto d128_mul_impl(const T1& lhs_sig, const U1 lhs_exp, const bool lhs const auto digit_delta {sig_dig - std::numeric_limits::digits10}; if (BOOST_DECIMAL_LIKELY(digit_delta > 0)) { - res_sig /= pow10(digit_delta); - res_exp += digit_delta; + auto biased_exp {res_exp + detail::bias_v}; + detail::coefficient_rounding(res_sig, res_exp, biased_exp, sign, sig_dig); } BOOST_DECIMAL_ASSERT((res_sig[3] | res_sig[2]) == 0U); From ea758023329e45c90be93b98e2d67dae358589fd Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 22 Jan 2026 08:39:22 -0500 Subject: [PATCH 4/5] Fix incomplete type compile failure on older compilers --- include/boost/decimal/detail/mul_impl.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/decimal/detail/mul_impl.hpp b/include/boost/decimal/detail/mul_impl.hpp index a1f81a9ce..7ec48e9ce 100644 --- a/include/boost/decimal/detail/mul_impl.hpp +++ b/include/boost/decimal/detail/mul_impl.hpp @@ -165,8 +165,8 @@ constexpr auto d128_mul_impl(const T1& lhs_sig, const U1 lhs_exp, const bool lhs const auto digit_delta {sig_dig - std::numeric_limits::digits10}; if (BOOST_DECIMAL_LIKELY(digit_delta > 0)) { - auto biased_exp {res_exp + detail::bias_v}; - detail::coefficient_rounding(res_sig, res_exp, biased_exp, sign, sig_dig); + auto biased_exp {res_exp + detail::bias_v}; + detail::coefficient_rounding(res_sig, res_exp, biased_exp, sign, sig_dig); } BOOST_DECIMAL_ASSERT((res_sig[3] | res_sig[2]) == 0U); From ad4173ed7624085ab8c9aab45d8d3d0d2e2941b4 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 22 Jan 2026 09:35:19 -0500 Subject: [PATCH 5/5] Fix type conflict on embedded --- include/boost/decimal/detail/fenv_rounding.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/decimal/detail/fenv_rounding.hpp b/include/boost/decimal/detail/fenv_rounding.hpp index 4674033e0..ae369d38d 100644 --- a/include/boost/decimal/detail/fenv_rounding.hpp +++ b/include/boost/decimal/detail/fenv_rounding.hpp @@ -202,7 +202,7 @@ constexpr auto coefficient_rounding(T1& coeff, T2& exp, T3& biased_exp, const bo using demoted_integer_type = std::conditional_t::digits10 < std::numeric_limits::digits10, T1, sig_type>; // How many digits need to be shifted? - const auto shift_for_large_coeff {(coeff_digits - detail::precision_v) - 1}; + const int shift_for_large_coeff {(coeff_digits - detail::precision_v) - 1}; int shift {}; BOOST_DECIMAL_IF_CONSTEXPR (is_fast_type_v) { @@ -212,7 +212,7 @@ constexpr auto coefficient_rounding(T1& coeff, T2& exp, T3& biased_exp, const bo } else { - const auto shift_for_small_exp {(-biased_exp) - 1}; + const auto shift_for_small_exp {static_cast((-biased_exp) - 1)}; shift = std::max(shift_for_small_exp, shift_for_large_coeff); }