Pretty Print Large Numbers

Introduction

The <utilities/thousands.h> header provides functions that help you print large numbers in a readable format by forcing a stream or locale to insert appropriate commas, e.g., having 23456.7 print as 23,456.7.

1utilities::imbue_stream_with_commas(std::ios_base &s = std::cout, bool on = true);
2utilities::imbue_global_with_commas(bool on = true);
3utilities::pretty_print_thousands(bool on = true);
1
Turns commas on or off for a particular stream.
2
Turns commas on or off for the global locale.
3
Turns commas on or off for the standard streams std::cout, std::cerr, std::clog, and the global locale.

Ideally, one should be able to rely on facilities in std::locale to format large numbers per local custom. For example, using std::format, you might print a large number like this:

std::cout << std::format("x = {:L}\n", 23456.7);

The L specifier tells the text formatting library to invoke an appropriate facet from the default locale. Then, you should see 23,456.7 printed on the screen for many locations.

In practice, the C++ standard libraries seem to have poor support for resolving locale information.

Your computer correctly supports locales at the operating system level. After all, computer manufacturers sell their machines to customers worldwide, and those customers expect to see dates, etc., presented locally. However, the default locale used in many C++ implementations is not the default one used by the operating system. Instead, it is often a complete blank, so rather than seeing 23,456.7 you will get the less readable 23456.7

The various utilities::imbue_xxx_with_commas functions are a little hack that corrects the deficit. If you call the final version above pretty_print_thousands(), we inject a comma-producing facet into the default locale, and printing large numbers will work as expected. Calling pretty_print_thousands(false) will restore the default locale to its original state.

For now, the only punctuation we support with these functions is the comma. You should know that many countries treat the comma as a decimal point.

Example

#include <utilities/thousands.h>
#include <format>

int main()
{
    double x = 123456789.123456789;

    std::cout << std::format("Using the default locale:\n");
    std::cout << std::format("No locale specifier:   {:12.5f}\n",    x);
1    std::cout << std::format("With locale specifier: {:12.5Lf}\n\n", x);

    utilities::pretty_print_thousands();
    std::cout << std::format("After adding a commas facet:\n");
    std::cout << std::format("No locale specifier:   {:12.5f}\n",   x);
2    std::cout << std::format("With locale specifier: {:12.5Lf}\n",  x);
}
1
We might expect to see a readable x here but typically will not.
2
We will see a readable x here for sure.

Output

Using the default locale:
No locale specifier:   123456789.12346
With locale specifier: 123456789.12346

After adding a commas facet:
No locale specifier:   123456789.12346
With locale specifier: 123,456,789.12346

See Also

std::format
std::locale

std::format: https://en.cppreference.com/w/cpp/utility/format/format

Back to top