|
1 | 1 | // Copyright 2024 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 examples demonstrates decimal floating point literals, |
| 6 | +// as well as numeric constants made available by the library |
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/decimal64_t.hpp> // For type decimal64_t |
| 10 | +#include <boost/decimal/literals.hpp> // For the decimal (user defined) literals |
| 11 | +#include <boost/decimal/numbers.hpp> // For provided numeric constants |
| 12 | +#include <boost/decimal/iostream.hpp> // For support to <iostream> and <iomanip> |
| 13 | +#include <iostream> |
| 14 | +#include <iomanip> |
| 15 | +#include <type_traits> |
| 16 | +#include <limits> |
7 | 17 |
|
8 | | -using namespace boost::decimal::literals; |
9 | | - |
10 | | -template <typename T> |
11 | | -bool float_equal(T lhs, T rhs) |
| 18 | +int main() |
12 | 19 | { |
13 | | - using std::fabs; |
14 | | - return fabs(lhs - rhs) < std::numeric_limits<T>::epsilon(); // numeric_limits is overloaded for all decimal types |
15 | | -} |
| 20 | + using namespace boost::decimal::literals; // Much like the std namespace, literals are separate form the lib |
| 21 | + using boost::decimal::decimal32_t; // Type decimal32_t |
| 22 | + using boost::decimal::decimal64_t; // Type decimal64_t |
16 | 23 |
|
| 24 | + // Defaulted numeric constants are available with type decimal64_t, |
| 25 | + // much like std::numbers::pi defaults to double |
| 26 | + constexpr auto default_pi {boost::decimal::numbers::pi}; |
| 27 | + using default_type = std::remove_cv_t<decltype(default_pi)>; |
| 28 | + static_assert(std::is_same<default_type, decimal64_t>::value, "Defaulted value has type decimal64_t"); |
17 | 29 |
|
18 | | -int main() |
19 | | -{ |
20 | | - using namespace boost::decimal; |
| 30 | + // You can also specify the type explicitly as these are template constants |
| 31 | + constexpr decimal32_t decimal32_pi {boost::decimal::numbers::pi_v<decimal32_t>}; |
21 | 32 |
|
22 | | - BOOST_DECIMAL_ATTRIBUTE_UNUSED const auto pi_32 {"3.141592653589793238"_DF}; |
23 | | - BOOST_DECIMAL_ATTRIBUTE_UNUSED const auto pi_64 {"3.141592653589793238"_DD}; |
| 33 | + // We can use std::setprecision from <iomanip> to see the real difference between the two values |
| 34 | + // numeric_limits is also specialized for each type |
| 35 | + std::cout << std::setprecision(std::numeric_limits<decimal32_t>::digits10) |
| 36 | + << "32-bit Pi: " << decimal32_pi << '\n'; |
24 | 37 |
|
25 | | - assert(float_equal(pi_32, static_cast<decimal32_t>(pi_64))); // Explicit conversion between decimal types |
26 | | - assert(float_equal(pi_32, boost::decimal::numbers::pi_v<decimal32_t>)); // Constants available in numbers namespace |
27 | | - assert(float_equal(pi_64, numbers::pi)); // Default constant type is decimal64_t |
| 38 | + std::cout << std::setprecision(std::numeric_limits<decimal64_t>::digits10) |
| 39 | + << "64-bit Pi: " << default_pi << '\n'; |
28 | 40 |
|
29 | | - return 0; |
30 | | -} |
| 41 | + // All of our types also offer user defined literals: |
| 42 | + // _df or _DF for decimal32_t |
| 43 | + // _dd or _DD for decimal64_t |
| 44 | + // _dl or _DL for decimal128_t |
| 45 | + // For fast types add an f to the end of each (e.g. _dff = decimal_fast32_t or _DLF decimal_fast128_t) |
| 46 | + // |
| 47 | + // Since we have specified the type using the literal it is safe to use auto for the type |
| 48 | + // |
| 49 | + // We construct both from the first 40 digits of pi |
| 50 | + // The constructor will parse this and then round to the proper precision automatically |
| 51 | + |
| 52 | + constexpr auto literal32_pi {"3.141592653589793238462643383279502884197"_DF}; |
| 53 | + constexpr auto literal64_pi {"3.141592653589793238462643383279502884197"_DD}; |
| 54 | + |
| 55 | + std::cout << std::setprecision(std::numeric_limits<decimal32_t>::digits10) |
| 56 | + << "32-bit UDL Pi: " << literal32_pi << '\n'; |
31 | 57 |
|
| 58 | + // Unlike built-in binary floating point, floating equal is acceptable with decimal floating point |
| 59 | + // Float equal will automatically address cohorts as per IEEE 754 if required (not shown in this example) |
| 60 | + if (literal32_pi == decimal32_pi) |
| 61 | + { |
| 62 | + std::cout << "Rounded UDL has the same value as the 32-bit constant" << '\n'; |
| 63 | + } |
32 | 64 |
|
| 65 | + std::cout << std::setprecision(std::numeric_limits<decimal64_t>::digits10) |
| 66 | + << "64-bit UDL Pi: " << literal64_pi << '\n'; |
| 67 | + |
| 68 | + if (literal64_pi == default_pi) |
| 69 | + { |
| 70 | + std::cout << "Rounded UDL has the same value as the 64-bit constant" << '\n'; |
| 71 | + } |
| 72 | +} |
0 commit comments