Skip to content

Commit 66b697f

Browse files
authored
Merge pull request #1128 from cppalliance/1112
Obey current rounding mode with rint/lrint/nearbyint
2 parents 7d44a84 + a9f3040 commit 66b697f

File tree

3 files changed

+73
-12
lines changed

3 files changed

+73
-12
lines changed

include/boost/decimal/detail/cmath/rint.hpp

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,20 +28,15 @@ namespace decimal {
2828

2929
namespace detail {
3030

31-
template <BOOST_DECIMAL_INTEGRAL T1, BOOST_DECIMAL_INTEGRAL T2>
32-
constexpr auto rint_impl(T1& sig, T2 exp, const bool)
31+
template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE TargetType, BOOST_DECIMAL_INTEGRAL T1, BOOST_DECIMAL_INTEGRAL T2>
32+
constexpr auto rint_impl(T1& sig, T2 exp, const bool is_neg)
3333
{
3434
const T2 abs_exp { (exp < T2(0)) ? -exp : exp };
3535

36-
sig /= detail::pow10(static_cast<T1>(abs_exp - 1));
36+
const auto res {detail::impl::divmod(sig, detail::pow10(static_cast<T1>(abs_exp - 1)))};
37+
sig = res.quotient;
3738

38-
const auto trailing_num {static_cast<std::uint32_t>(sig % 10U)};
39-
sig /= 10U;
40-
41-
if (trailing_num >= 5U)
42-
{
43-
++sig;
44-
}
39+
detail::fenv_round<TargetType>(sig, is_neg, res.remainder != 0U);
4540
}
4641

4742
// 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
9792
return 0;
9893
}
9994

100-
detail::rint_impl(sig, expptr, is_neg);
95+
detail::rint_impl<T>(sig, expptr, is_neg);
10196

10297
auto res {static_cast<Int>(sig)};
10398
if (is_neg)
@@ -147,7 +142,7 @@ constexpr auto rint(const T num) noexcept
147142
return is_neg ? -zero : zero;
148143
}
149144

150-
detail::rint_impl(sig, expptr, is_neg);
145+
detail::rint_impl<T>(sig, expptr, is_neg);
151146

152147
return {sig, 0, is_neg};
153148
}

test/Jamfile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ run-fail benchmark_uint256.cpp ;
4848

4949
run compare_dec128_and_fast.cpp ;
5050
compile-fail concepts_test.cpp ;
51+
5152
run crash_report_1.cpp ;
5253
run github_issue_426.cpp ;
5354
run github_issue_448.cpp ;
@@ -69,6 +70,8 @@ run github_issue_1057.cpp ;
6970
compile-fail github_issue_1087.cpp ;
7071
run github_issue_1091.cpp ;
7172
run github_issue_1094.cpp ;
73+
run github_issue_1112.cpp ;
74+
7275
run link_1.cpp link_2.cpp link_3.cpp ;
7376
run quick.cpp ;
7477
run random_decimal32_comp.cpp ;

test/github_issue_1112.cpp

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// Copyright 2025 Matt Borland
2+
// Distributed under the Boost Software License, Version 1.0.
3+
// https://www.boost.org/LICENSE_1_0.txt
4+
//
5+
// See: https://github.com/cppalliance/decimal/issues/1112
6+
7+
#include <boost/decimal.hpp>
8+
#include <boost/core/lightweight_test.hpp>
9+
#include <random>
10+
11+
static std::mt19937_64 rng(42);
12+
std::uniform_int_distribution<> dist(-1, -1);
13+
14+
using namespace boost::decimal;
15+
16+
template <typename T>
17+
void reproducer()
18+
{
19+
const auto dec_res {static_cast<int>(nearbyint(T{2325, -1}))};
20+
const auto dbl_res {static_cast<int>(std::nearbyint(232.5))};
21+
BOOST_TEST_EQ(dec_res, dbl_res);
22+
}
23+
24+
template <typename T>
25+
void test_rounding_up()
26+
{
27+
const auto mode {boost::decimal::fesetround(rounding_mode::fe_dec_upward)};
28+
if (mode != rounding_mode::fe_dec_default)
29+
{
30+
const T value {2325, dist(rng)}; // The result will be wrong if computed at compile time
31+
const auto dec_res {static_cast<int>(nearbyint(value))};
32+
BOOST_TEST_EQ(dec_res, 233);
33+
}
34+
}
35+
36+
template <typename T>
37+
void test_rounding_down()
38+
{
39+
const auto mode {boost::decimal::fesetround(rounding_mode::fe_dec_downward)};
40+
if (mode != rounding_mode::fe_dec_default)
41+
{
42+
const T value {2325, dist(rng)}; // The result will be wrong if computed at compile time
43+
const auto dec_res {static_cast<int>(nearbyint(value))};
44+
BOOST_TEST_EQ(dec_res, 232);
45+
}
46+
}
47+
48+
int main()
49+
{
50+
reproducer<decimal32_t>();
51+
reproducer<decimal64_t>();
52+
reproducer<decimal128_t>();
53+
54+
test_rounding_up<decimal32_t>();
55+
test_rounding_up<decimal64_t>();
56+
test_rounding_up<decimal128_t>();
57+
58+
test_rounding_down<decimal32_t>();
59+
test_rounding_down<decimal64_t>();
60+
test_rounding_down<decimal128_t>();
61+
62+
return boost::report_errors();
63+
}

0 commit comments

Comments
 (0)