Formatting Support

Boost.Decimal supports formatting with both <format> (when C++20 and header are both available), and <fmt/format.h> with all language standards.

Format is supported when using C++20 and a compiler with appropriate support: GCC >= 13, Clang >= 18, MSVC >= 19.40

Locale Modifier

If a format string begins with "L" the current global locale will be applied. This can be set as so:

// Locale can be any valid locale that is installed on your system
const char* locale = "de_DE.UTF-8";
const std::locale a(locale);
std::locale::global(a);

Sign Modifier

Modifier

Format

"+"

All values will have a sign

"-"

Only negative values have a sign

" "

Positive values have a leading space, Negative have a minus sign

Type Modifiers

The following type modifiers are the same as those used by built-in floating point values:

Modifier

Format

"g" or "G"

General

"e" or "E"

Scientific

"f"

Fixed

"x" or "X"

Hex

"a" or "A"

Cohort Preserving Scientific

Example usage for scientific format would be: {:e}

The uppercase format will return with all applicable values in uppercase (e.g. 3.14E+02 vs 3.14e+02)

Precision Modifiers

Precision can be specified in the same way as built-in floating point values. For example a scientific format with 3 digits or precision would be: {:.3e}

Padding Modifiers

If you want all values to be printed with a fixed width padding is allowed before the precision modifier. For example with {:10.3e}:

  • 3.14 → " 3.140e+00"

  • 3.141 → " 3.141e+00"

Note the space at the front of these string to keep with width at 10 characters

String Literal Support

If you want the result to be a different string width than char you can specify this with the format string. For example if you want the result to be wchar_t you can use L"{}". wchar_t, char16_t, char32_t are supported from C++17. char8_t is supported from C++23.

std::format only supports char and wchar_t types per the C++ specification.

Putting it All Together

The appropriate order for the full format specifier is:

String literal "{Sign, Padding, Precision, Type, Locale}"

Examples

This example can be found in the examples/ folder as fmt_format.cpp

The header <boost/decimal/fmt_format.hpp> is NOT part of the convenience header, because it is an optional dependency on a potentially compiled library.

#include <fmt/format.h>
#include <boost/decimal.hpp>
#include <boost/decimal/fmt_format.hpp>
#include <iostream>

int main()
{
    constexpr boost::decimal::decimal64_t val1 {"3.14"};
    constexpr boost::decimal::decimal32_t val2 {"3.141"};

    // The easiest is no specification which is general format
    // Given these values they will print in fixed format
    std::cout << "Default Format:\n";
    std::cout << fmt::format("{}", val1) << '\n';
    std::cout << fmt::format("{}", val2) << "\n\n";

    // Next we can add a type modifier to get scientific formatting
    std::cout << "Scientific Format:\n";
    std::cout << fmt::format("{:e}", val1) << '\n';
    std::cout << fmt::format("{:e}", val2) << "\n\n";

    // Next we can add a type modifier to get scientific formatting
    // Here this gives one digit of precision rounded according to current rounding mode
    std::cout << "Scientific Format with Specified Precision:\n";
    std::cout << fmt::format("{:.1e}", val1) << '\n';
    std::cout << fmt::format("{:.1e}", val2) << "\n\n";

    // This combines the padding modifier (10), precision (3 digits), and a type modifier (e)
    std::cout << "Scientific Format with Specified Precision and Padding:\n";
    std::cout << fmt::format("{:10.3e}", val1) << '\n';
    std::cout << fmt::format("{:10.3e}", val2) << '\n';

    return 0;
}

Output:

Default Format:
3.14
3.141

Scientific Format:
3.14e+00
3.141e+00

Scientific Format with Specified Precision:
3.1e+00
3.1e+00

Scientific Format with Specified Precision and Padding:
03.140e+00
03.141e+00

This same example can be run with <format> by replacing namespaces fmt:: with std::.