|
1 | | -// Copyright 2024 Matt Borland |
| 1 | +// Copyright 2024 - 2025 Matt Borland |
2 | 2 | // Distributed under the Boost Software License, Version 1.0. |
3 | 3 | // https://www.boost.org/LICENSE_1_0.txt |
| 4 | +// |
| 5 | +// This example demonstrates how to set and get the global rounding mode |
| 6 | +// as well as the effects on numerical results |
4 | 7 |
|
5 | | -#include <boost/decimal.hpp> |
6 | | -#include <cassert> |
| 8 | +#include <boost/decimal/decimal32_t.hpp> // For type decimal32_t |
| 9 | +#include <boost/decimal/literals.hpp> // For decimal literals |
| 10 | +#include <boost/decimal/cfenv.hpp> // For access to the rounding mode functions |
| 11 | +#include <boost/decimal/iostream.hpp> // Decimal support to <iostream> |
| 12 | +#include <iostream> |
| 13 | + |
| 14 | +void print_rounding_mode(const boost::decimal::rounding_mode current_mode) |
| 15 | +{ |
| 16 | + // All 5 rounding modes are defined by the enum rounding_mode |
| 17 | + using boost::decimal::rounding_mode; |
| 18 | + |
| 19 | + switch (current_mode) |
| 20 | + { |
| 21 | + case rounding_mode::fe_dec_downward: |
| 22 | + std::cout << "fe_dec_downward\n"; |
| 23 | + break; |
| 24 | + case rounding_mode::fe_dec_to_nearest: |
| 25 | + std::cout << "fe_dec_to_nearest\n"; |
| 26 | + break; |
| 27 | + case rounding_mode::fe_dec_to_nearest_from_zero: |
| 28 | + std::cout << "fe_dec_to_nearest_from_zero\n"; |
| 29 | + break; |
| 30 | + case rounding_mode::fe_dec_toward_zero: |
| 31 | + std::cout << "fe_dec_toward_zero\n"; |
| 32 | + break; |
| 33 | + case rounding_mode::fe_dec_upward: |
| 34 | + std::cout << "fe_dec_upward\n"; |
| 35 | + break; |
| 36 | + } |
| 37 | +} |
7 | 38 |
|
8 | 39 | int main() |
9 | 40 | { |
10 | | - #ifndef BOOST_DECIMAL_NO_CONSTEVAL_DETECTION |
| 41 | + // The rounding mode can only be changed at run-time if the compiler supports |
| 42 | + // 1. C++20 std::is_constant_evaluated() |
| 43 | + // 2. Intrinsics that do the same |
| 44 | + // If neither of the above are defined the library defines BOOST_DECIMAL_NO_CONSTEVAL_DETECTION |
11 | 45 |
|
12 | | - using namespace boost::decimal::literals; |
| 46 | + // The current rounding mode can be queried with boost::decimal::fegetround |
| 47 | + const boost::decimal::rounding_mode default_rounding_mode = boost::decimal::fegetround(); |
| 48 | + std::cout << "The default rounding mode is: "; |
| 49 | + print_rounding_mode(default_rounding_mode); |
13 | 50 |
|
14 | | - BOOST_DECIMAL_ATTRIBUTE_UNUSED auto default_rounding_mode = boost::decimal::fegetround(); // Default is fe_dec_to_nearest |
| 51 | + // To set a new rounding mode use boost::decimal::fesetround |
| 52 | + // fesetround returns current mode after updating the global state |
| 53 | + // |
| 54 | + // If your compiler set defines BOOST_DECIMAL_NO_CONSTEVAL_DETECTION the global state can not be updated, |
| 55 | + // so this can be a useful check to make sure that state is what you expect it to be |
| 56 | + auto new_rounding_mode = boost::decimal::fesetround(boost::decimal::rounding_mode::fe_dec_upward); |
| 57 | + std::cout << "The current rounding mode is: "; |
| 58 | + print_rounding_mode(new_rounding_mode); |
15 | 59 |
|
16 | | - BOOST_DECIMAL_ATTRIBUTE_UNUSED auto new_rounding_mode = boost::decimal::fesetround(boost::decimal::rounding_mode::fe_dec_upward); |
| 60 | + #ifndef BOOST_DECIMAL_NO_CONSTEVAL_DETECTION |
| 61 | + |
| 62 | + using namespace boost::decimal::literals; |
| 63 | + using boost::decimal::decimal32_t; |
17 | 64 |
|
18 | | - assert(default_rounding_mode != new_rounding_mode); |
| 65 | + const decimal32_t lhs {"5e+50"_DF}; |
| 66 | + const decimal32_t rhs {"4e+40"_DF}; |
19 | 67 |
|
20 | | - const auto lhs {"5e+50"_DF}; |
21 | | - const auto rhs {"4e+40"_DF}; |
| 68 | + std::cout << "lhs equals: " << lhs << '\n' |
| 69 | + << "rhs equals: " << rhs << '\n'; |
22 | 70 |
|
23 | 71 | // With upward rounding the result will be "5.000001e+50"_DF |
24 | 72 | // Even though the difference in order of magnitude is greater than the precision of the type, |
25 | 73 | // any addition in this mode will result in at least a one ULP difference |
26 | | - BOOST_DECIMAL_ATTRIBUTE_UNUSED const auto upward_res {lhs + rhs}; |
27 | | - assert(upward_res == "5.000001e+50"_DF); |
| 74 | + const decimal32_t upward_res {lhs + rhs}; |
| 75 | + std::cout << " Sum with upward rounding: " << upward_res << '\n'; |
28 | 76 |
|
29 | | - boost::decimal::fesetround(boost::decimal::rounding_mode::fe_dec_downward); |
| 77 | + |
| 78 | + new_rounding_mode = boost::decimal::fesetround(boost::decimal::rounding_mode::fe_dec_downward); |
| 79 | + std::cout << "The current rounding mode is: "; |
| 80 | + print_rounding_mode(new_rounding_mode); |
30 | 81 |
|
31 | 82 | // Similar to above in the downward rounding mode any subtraction will result in at least a one ULP difference |
32 | | - BOOST_DECIMAL_ATTRIBUTE_UNUSED const auto downward_res {lhs - rhs}; |
33 | | - assert(downward_res == "4.999999e+50"_DF); |
| 83 | + const decimal32_t downward_res {lhs - rhs}; |
| 84 | + std::cout << "Sum with downward rounding: " << downward_res << '\n'; |
34 | 85 |
|
35 | 86 | #endif // BOOST_DECIMAL_NO_CONSTEVAL_DETECTION |
36 | | - |
37 | | - return 0; |
38 | 87 | } |
39 | | - |
|
0 commit comments