Skip to content

Commit 529c490

Browse files
authored
Merge pull request #1285 from cppalliance/conversions
2 parents 4f83ea0 + 1dab453 commit 529c490

File tree

4 files changed

+106
-0
lines changed

4 files changed

+106
-0
lines changed

doc/modules/ROOT/nav.adoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
* xref:examples.adoc[]
44
** xref:examples.adoc#examples_construction[Basic Construction]
55
** xref:examples.adoc#examples_basic_math[Basic Arithmetic]
6+
** xref:examples.adoc#examples_conversions[Conversions]
7+
*** xref:examples.adoc#examples_binary_floating_conversions[Binary Floating Point]
68
** xref:examples.adoc#examples_promotion[Promotion and Mixed Decimal Arithmetic]
79
** xref:examples.adoc#examples_charconv[`<charconv>`]
810
** xref:examples.adoc#examples_generic_programming[Generic Programming]

doc/modules/ROOT/pages/examples.adoc

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,30 @@ Decimal Result: 100
6969
....
7070
====
7171
72+
[#examples_conversions]
73+
== Conversions
74+
75+
[#examples_binary_floating_conversions]
76+
=== Binary Floating Point Conversions
77+
78+
.This https://github.com/cppalliance/decimal/blob/develop/examples/binary_float_conversions.cpp[example] shows show to construct a binary floating point value from decimal type and vice versa
79+
====
80+
[source,c++]
81+
----
82+
include::example$binary_float_conversions.cpp[]
83+
----
84+
85+
.Expected Output:
86+
....
87+
Decimal QNAN converts to double QNAN
88+
Decimal INFINITY converts to double INFINITY
89+
decimal64_t pi: 3.141592653589793
90+
double pi: 3.141592653589793
91+
Converted pi: 3.141592653589793
92+
decimal32_t pi: 3.141593
93+
....
94+
====
95+
7296
[#examples_promotion]
7397
== Promotion and Mixed Decimal Arithmetic
7498
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)