From 2a3bc581c7d6b38c1122ee8c7c8d0e31dd58364e Mon Sep 17 00:00:00 2001 From: Shen-Ta Hsieh Date: Fri, 25 Sep 2026 07:18:03 +0800 Subject: [PATCH] Use the optimized multiply path for decimal32_t - decimal32_t * decimal32_t gave the raw product to the constructor, and did not use the faster path of the other types. - That path rounds to 7 digits before pack_in_range, and the constructor then rounds a subnormal result again. Thus a product with an exponent below etiny still goes to the constructor unrounded. Above etiny, the rounded result has 7 digits or is at least 1e-94, so one rounding is correct. - decimal32_t * Integer keeps the constructor path, because the optimized path gives a zero product a different exponent. - The results are bit-identical to the old path in all five rounding modes. --- include/boost/decimal/detail/mul_impl.hpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/include/boost/decimal/detail/mul_impl.hpp b/include/boost/decimal/detail/mul_impl.hpp index 6411feb5a..6308539eb 100644 --- a/include/boost/decimal/detail/mul_impl.hpp +++ b/include/boost/decimal/detail/mul_impl.hpp @@ -204,12 +204,9 @@ BOOST_DECIMAL_FORCE_INLINE BOOST_DECIMAL_CUDA_CONSTEXPR auto mul_impl_dispatch( using mul_type = std::conditional_t; const bool sign {lhs_c.sign != rhs_c.sign}; - // d32 IEEE: revert to the simple multiply + constructor handoff. The - // hardware uint64 divide the constructor's coefficient_rounding does - // is already cheap enough that the expand + pre-shrink + direct_pack - // path's overhead doesn't pay off here. d32_fast still benefits and - // continues to use the optimized path below. - BOOST_DECIMAL_IF_CONSTEXPR (std::is_same::value) + // d32 IEEE: a product below the subnormal exponent goes to the constructor + // unrounded, because the optimized path below would round it twice. + if (std::is_same::value && BOOST_DECIMAL_UNLIKELY(lhs_c.exp + rhs_c.exp < etiny_v)) { const auto res_sig {static_cast(lhs_c.sig) * static_cast(rhs_c.sig)}; const auto res_exp {lhs_c.exp + rhs_c.exp}; @@ -325,8 +322,8 @@ BOOST_DECIMAL_FORCE_INLINE BOOST_DECIMAL_CUDA_CONSTEXPR auto mul_impl(T lhs_sig, const bool sign {lhs_sign != rhs_sign}; - // d32 IEEE: revert to the simple multiply + constructor handoff (see - // generic mul_impl above for rationale). + // d32 IEEE: keep the simple multiply + constructor handoff, because the + // path below gives a zero product a different exponent. BOOST_DECIMAL_IF_CONSTEXPR (std::is_same::value) { const auto res_sig {static_cast(lhs_sig) * static_cast(rhs_sig)};