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

Simple Moving Average

In the examples folder there is a file named moving_average.cpp. This example shows how to parse historical stock data from file and use it. This serves as a framework for other calculations for securities.

Currency Conversion

In the examples folder there is a file named currency_conversion.cpp. This example shows how to simply convert currencies based off a given exchange rate.

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;
}