Skip to content

Commit 3958fbd

Browse files
committed
Add example on binary floating point conversions
1 parent 4f83ea0 commit 3958fbd

File tree

2 files changed

+80
-0
lines changed

2 files changed

+80
-0
lines changed
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
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+
// This file demonstrates how to convert various types to decimal types and back,
6+
// along with edge case handling
7+
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/cmath.hpp> // For decimal support of cmath functions
11+
#include <boost/decimal/iostream.hpp> // For decimal support of <iostream> and <iomanip>
12+
#include <boost/decimal/numbers.hpp> // For decimal support of <numbers>
13+
#include <iostream>
14+
#include <cmath>
15+
#include <limits>
16+
17+
int main()
18+
{
19+
using boost::decimal::decimal32_t; // Type decimal32_t
20+
using boost::decimal::decimal64_t; // Type decimal64_t
21+
22+
// Non-finite values construct the equivalent non-finite value in binary floating point
23+
constexpr decimal64_t decimal_qnan {std::numeric_limits<decimal64_t>::quiet_NaN()};
24+
const double double_from_qnan {static_cast<double>(decimal_qnan)};
25+
26+
// Note here that we must use boost::decimal::isnan for decimal types,
27+
// as it is illegal to overload std::isnan
28+
if (boost::decimal::isnan(decimal_qnan) && std::isnan(double_from_qnan))
29+
{
30+
std::cout << "Decimal QNAN converts to double QNAN\n";
31+
}
32+
33+
constexpr decimal64_t decimal_inf {std::numeric_limits<decimal64_t>::infinity()};
34+
const double double_from_inf {static_cast<double>(decimal_inf)};
35+
36+
// Same as the above but with INF instead of NAN
37+
if (boost::decimal::isinf(decimal_inf) && std::isinf(double_from_inf))
38+
{
39+
std::cout << "Decimal INFINITY converts to double INFINITY\n";
40+
}
41+
42+
// For finite values we make a best effort approach to covert to double
43+
// We are able to decompose the decimal floating point value into a sign, significand, and exponent.
44+
// From there we use the methods outline in Daniel Lemire's "Number Parsing at a Gigabyte a Second",
45+
// to construct the binary floating point value.
46+
// See: https://arxiv.org/pdf/2101.11408
47+
48+
// Construct the decimal64_t version of pi using our pre-computed constants from <boost/decimal/numbers.hpp>
49+
constexpr decimal64_t decimal_pi {boost::decimal::numbers::pi_v<decimal64_t>};
50+
const double double_from_pi {static_cast<double>(decimal_pi)};
51+
52+
std::cout << std::setprecision(std::numeric_limits<decimal64_t>::digits10)
53+
<< "decimal64_t pi: " << decimal_pi << '\n'
54+
<< " double pi: " << double_from_pi << '\n';
55+
56+
// To construct a decimal64_t from double we use the methods described in "Ryu: fast float-to-string conversion"
57+
// See: https://dl.acm.org/doi/10.1145/3192366.3192369
58+
// This paper shows how to decompose a double into it's sign, significand, and exponent
59+
// Once we have those components we can use the normal constructors of the decimal types to construct
60+
// Since we are using the normal constructors here,
61+
// any construction from this conversion is subject to the current rounding mode
62+
// Such as with a lossy conversion like shown (double -> decimal32_t)
63+
64+
const decimal64_t decimal_from_double {static_cast<decimal64_t>(double_from_pi)};
65+
const decimal32_t lossy_decimal_from_double {static_cast<decimal32_t>(double_from_pi)};
66+
67+
std::cout << " Converted pi: " << decimal_from_double << '\n'
68+
<< "decimal32_t pi: " << lossy_decimal_from_double << '\n';
69+
70+
71+
// Other than what has already been shown,
72+
// there are no other ways in the library to convert between decimal types and binary floating point types
73+
// The reason for this is to discourage their use.
74+
//
75+
// You can use intermediate representations like strings if you want to make these conversions,
76+
// and want to be sure about what the resulting value will be
77+
78+
return 0;
79+
}

test/Jamfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ run ../examples/basic_arithmetic.cpp ;
215215
run ../examples/to_from_file.cpp ;
216216
run ../examples/addition.cpp ;
217217
run ../examples/debugger.cpp ;
218+
run ../examples/binary_float_conversions.cpp ;
218219

219220
# Test compilation of separate headers
220221
compile compile_tests/bid_conversion.cpp ;

0 commit comments

Comments
 (0)