Examples
All examples can be found in the library examples/
folder as well.
Construction from an Integer and Exponent
#include <boost/decimal.hpp>
#include <iostream>
int main()
{
constexpr boost::decimal::decimal32_t a {2, -1}; // Constructs the number 0.2
constexpr boost::decimal::decimal32_t b {1, -1}; // Constructs the number 0.1
boost::decimal::decimal32_t sum {a + b};
std::cout << sum << std::endl; // prints 0.3
const boost::decimal::decimal32_t neg_a {2, -1, true}; // Constructs the number -0.2
sum += neg_a;
std::cout << sum << std::endl; // Prints 0.1
return 0;
}
This is the recommended way of constructing a fractional number as opposed to decimal32_t a {0.2}
.
The representation is exact with integers whereas you may get surprising or unwanted conversion from binary floating point
Promotion
#include <boost/decimal.hpp>
#include <type_traits>
#include <cassert>
int main()
{
using namespace boost::decimal;
decimal32_t x {1}; // Constructs from an integer
decimal64_t y {2};
auto sum {x + y};
assert(std::is_same<decimal64_t, decltype(sum)>::value);
return 0;
}
charconv
#include <boost/decimal.hpp>
#include <iostream>
#include <cassert>
int main()
{
using namespace boost::decimal;
decimal64_t val {0.25}; // Construction from a double (not recommended but explicit construction is allowed)
char buffer[256];
auto r_to = to_chars(buffer, buffer + sizeof(buffer) - 1, val);
assert(r_to); // checks std::errc()
*r_to.ptr = '\0';
decimal64_t return_value;
auto r_from = from_chars(buffer, buffer + std::strlen(buffer), return_value);
assert(r_from);
assert(val == return_value);
std::cout << " Initial Value: " << val << '\n'
<< "Returned Value: " << return_value << std::endl;
return 0;
}
Output:
Initial Value: 0.25 Returned Value: 0.25
Rounding Mode
#include <boost/decimal.hpp>
#include <cassert>
int main()
{
auto default_rounding_mode = boost::decimal::fegetround(); // Default is fe_dec_to_nearest_from_zero
auto new_rounding_mode = boost::decimal::fesetround(boost::decimal::rounding_mode::fe_dec_to_nearest);
assert(default_rounding_mode != new_rounding_mode);
return 0;
}
Generic Programming
#include <boost/decimal.hpp>
#include <limits>
#include <cmath>
int error_counter = 0;
template <typename T>
bool float_equal(T lhs, T rhs)
{
using std::fabs;
return fabs(lhs - rhs) < std::numeric_limits<T>::epsilon(); // numeric_limits is overloaded for all decimal types
}
template <typename T>
void test(T val)
{
using std::sin; // ADL allows builtin and decimal types to both be used
if (!float_equal(sin(val), -sin(-val))) // sin(x) == -sin(-x)
{
++error_counter;
}
}
int main()
{
test(-0.5F);
test(-0.5);
test(-0.5L);
test(boost::decimal::decimal32_t{5, -1, true});
test(boost::decimal::decimal64_t{5, -1, true});
test(boost::decimal::decimal128_t{5, -1, true});
return error_counter;
}
Literals and Constants
#include <boost/decimal.hpp>
#include <cassert>
template <typename T>
bool float_equal(T lhs, T rhs)
{
using std::fabs;
return fabs(lhs - rhs) < std::numeric_limits<T>::epsilon(); // numeric_limits is overloaded for all decimal types
}
int main()
{
using namespace boost::decimal;
const auto pi_32 {"3.141592653589793238"_DF};
const auto pi_64 {"3.141592653589793238"_DD};
assert(float_equal(pi_32, static_cast<decimal32_t>(pi_64))); // Explicit conversion between decimal types
assert(float_equal(pi_32, boost::decimal::numbers::pi_v<decimal32_t>)); // Constants available in numbers namespace
assert(float_equal(pi_64, numbers::pi)); // Default constant type is decimal64_t
return 0;
}
Bit Conversions
#include <boost/decimal.hpp>
#include <iostream>
#include <iomanip>
using namespace boost::decimal;
int main()
{
const decimal_fast32_t fast_type {5};
const std::uint32_t BID_bits {to_bid(fast_type)};
const std::uint32_t DPD_bits {to_dpd(fast_type)};
std::cout << std::hex
<< "BID format: " << BID_bits << '\n'
<< "DPD format: " << DPD_bits << std::endl;
const decimal32_t bid_decimal {from_bid<decimal32_t>(BID_bits)};
const decimal32_t dpd_decimal {from_dpd<decimal32_t>(DPD_bits)};
return !(bid_decimal == dpd_decimal);
}
Output:
BID format: 31fc4b40 DPD format: 35f00000
Financial Applications
Boost.Math Integration
Bollinger Bands
In the examples folder there is a file named statistics.cpp
.
This example demonstrates how to parse a file, and then leverage Boost.Math to compute statistics of that data set culminating with the values of the Bollinger Bands.
This example could be extended with the simple moving average to create full bands based on the period of the moving average you would like.
Formatting
Boost.Decimal allows you to format your output with both <format>
and <fmt/format.h>
depending on your compiler support.
<format>
If your compiler provides <format>
you can use that to format the output of your values:
#include <boost/decimal.hpp>
#include <iostream>
#include <format>
int main()
{
constexpr boost::decimal::decimal64_t val1 {314, -2};
constexpr boost::decimal::decimal32_t val2 {3141, -3};
std::cout << std::format("{:10.3e}", val1) << '\n';
std::cout << std::format("{:10.3e}", val2) << std::endl;
return 0;
}
<fmt/format.hpp>
We also provide support for {fmt}
so you can easily just swap the namespaces and headers on the above example:
#include <boost/decimal.hpp>
#include <iostream>
#include <fmt/format.h>
int main()
{
constexpr boost::decimal::decimal64_t val1 {314, -2};
constexpr boost::decimal::decimal32_t val2 {3141, -3};
std::cout << fmt::format("{:10.3e}", val1) << '\n';
std::cout << fmt::format("{:10.3e}", val2) << std::endl;
return 0;
}
<print>
We can make one final change to our <format>
example where instead of using std::cout
, we use C++23's <print>
:
#include <boost/decimal.hpp>
#include <print>
int main()
{
constexpr boost::decimal::decimal64_t val1 {314, -2};
constexpr boost::decimal::decimal32_t val2 {3141, -3};
std::print("{:10.3e}\n", val1);
std::print("{:10.3e}\n", val2);
return 0;
}