diff --git a/include/boost/decimal/detail/cmath/rint.hpp b/include/boost/decimal/detail/cmath/rint.hpp index b087931a8..1e01a4fd0 100644 --- a/include/boost/decimal/detail/cmath/rint.hpp +++ b/include/boost/decimal/detail/cmath/rint.hpp @@ -28,20 +28,15 @@ namespace decimal { namespace detail { -template -constexpr auto rint_impl(T1& sig, T2 exp, const bool) +template +constexpr auto rint_impl(T1& sig, T2 exp, const bool is_neg) { const T2 abs_exp { (exp < T2(0)) ? -exp : exp }; - sig /= detail::pow10(static_cast(abs_exp - 1)); + const auto res {detail::impl::divmod(sig, detail::pow10(static_cast(abs_exp - 1)))}; + sig = res.quotient; - const auto trailing_num {static_cast(sig % 10U)}; - sig /= 10U; - - if (trailing_num >= 5U) - { - ++sig; - } + detail::fenv_round(sig, is_neg, res.remainder != 0U); } // MSVC 14.1 warns of unary minus being applied to unsigned type from numeric_limits::min @@ -97,7 +92,7 @@ constexpr auto lrint_impl(const T num) noexcept -> Int return 0; } - detail::rint_impl(sig, expptr, is_neg); + detail::rint_impl(sig, expptr, is_neg); auto res {static_cast(sig)}; if (is_neg) @@ -147,7 +142,7 @@ constexpr auto rint(const T num) noexcept return is_neg ? -zero : zero; } - detail::rint_impl(sig, expptr, is_neg); + detail::rint_impl(sig, expptr, is_neg); return {sig, 0, is_neg}; } diff --git a/test/Jamfile b/test/Jamfile index dc1b781dc..66f1b598c 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -48,6 +48,7 @@ run-fail benchmark_uint256.cpp ; run compare_dec128_and_fast.cpp ; compile-fail concepts_test.cpp ; + run crash_report_1.cpp ; run github_issue_426.cpp ; run github_issue_448.cpp ; @@ -69,6 +70,8 @@ run github_issue_1057.cpp ; compile-fail github_issue_1087.cpp ; run github_issue_1091.cpp ; run github_issue_1094.cpp ; +run github_issue_1112.cpp ; + run link_1.cpp link_2.cpp link_3.cpp ; run quick.cpp ; run random_decimal32_comp.cpp ; diff --git a/test/github_issue_1112.cpp b/test/github_issue_1112.cpp new file mode 100644 index 000000000..253bda161 --- /dev/null +++ b/test/github_issue_1112.cpp @@ -0,0 +1,63 @@ +// Copyright 2025 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt +// +// See: https://github.com/cppalliance/decimal/issues/1112 + +#include +#include +#include + +static std::mt19937_64 rng(42); +std::uniform_int_distribution<> dist(-1, -1); + +using namespace boost::decimal; + +template +void reproducer() +{ + const auto dec_res {static_cast(nearbyint(T{2325, -1}))}; + const auto dbl_res {static_cast(std::nearbyint(232.5))}; + BOOST_TEST_EQ(dec_res, dbl_res); +} + +template +void test_rounding_up() +{ + const auto mode {boost::decimal::fesetround(rounding_mode::fe_dec_upward)}; + if (mode != rounding_mode::fe_dec_default) + { + const T value {2325, dist(rng)}; // The result will be wrong if computed at compile time + const auto dec_res {static_cast(nearbyint(value))}; + BOOST_TEST_EQ(dec_res, 233); + } +} + +template +void test_rounding_down() +{ + const auto mode {boost::decimal::fesetround(rounding_mode::fe_dec_downward)}; + if (mode != rounding_mode::fe_dec_default) + { + const T value {2325, dist(rng)}; // The result will be wrong if computed at compile time + const auto dec_res {static_cast(nearbyint(value))}; + BOOST_TEST_EQ(dec_res, 232); + } +} + +int main() +{ + reproducer(); + reproducer(); + reproducer(); + + test_rounding_up(); + test_rounding_up(); + test_rounding_up(); + + test_rounding_down(); + test_rounding_down(); + test_rounding_down(); + + return boost::report_errors(); +}