Formatting floats: returning to default

Viewed 809

I am running into a formatting issue on floating-point values, in the sense of returning to "default formatting". Say I have 2 floats:

float f1 = 3.0f, f2 = 1.5f;
std::cout << f1 << " - " << f2 << "\n";

will show these as: 3 - 1.5

Now, for some reason, I need to set precision on std::cout (for other printing):

cout << std::precision(2);

If I print again my two floats, this will lead to: 3.00 - 1.50

Now I want to get back to default formatting. Until C++11 this seems to be difficult (or was it ?). But, thanks, I now got this new flag: std::defaultfloat. Lets try:

std::cout << std::defaultfloat << f1 << " - " << f2;

will print: 3 - 1.50. Fine.

Oh, but wait. Say I have instead:

float f1 = 444.0f, f2 = 444.5f;

Default printing will show: 444 - 444.5

Setting precision (and "fixed"):

cout << std::precision(2) << std::fixed;

will show: 444.00 - 444.50

But returning to "default":

std::cout << std::defaultfloat << f1 << " - " << f2;

will print: 4.4e+02 - 4.4e+02 (automatic switching to scientific format). And, in case you wonder, appending the "fixed" flag will keep the previously assigned precision, thus not returning back to original setting.

Question: How do I get back to the default mode ?

FWIW, live code is here.

Edit: this question has been tagged as a dupe but the linked answer does not provide an answer to the question, it only mentions how to get the current precision.

Edit 2: upon request, here is the full code demonstrating the issue:

int main()
{
    float f1 = 444.5f, f2=443.0f;
    std::cout << f1 << " - " << f2 << "\n";
    std::cout << std::fixed << std::setprecision(2);
    std::cout << f1 << " - " << f2 << "\n";
    std::cout << std::defaultfloat;
    std::cout << f1 << " - " << f2 << "\n";
}

And the result:

444.5 - 443
444.50 - 443.00
4.4e+02 - 4.4e+02
4 Answers

In C++20 you can use std::format which is a stateless API. In particular, specifying the precision in one call won't affect the other:

float f1 = 444.0f, f2 = 444.5f;
std::cout << std::format("{} - {}\n", f1, f2);
// Output: 444 - 444.5
std::cout << std::format("{:.2f} - {:.2f}\n", f1, f2);
// Output: 444.00 - 444.50
std::cout << std::format("{} - {}\n", f1, f2);
// Output: 444 - 444.5

std::format is not widely available yet but you can use the {fmt} library, std::format is based on, in the meantime. It also provides a print function that combines formatting and I/O:

float f1 = 444.0f, f2 = 444.5f;
fmt::print("{} - {}\n", f1, f2);
// Output: 444 - 444.5
fmt::print("{:.2f} - {:.2f}\n", f1, f2);
// Output: 444.00 - 444.50
fmt::print("{} - {}\n", f1, f2);
// Output: 444 - 444.5

Disclaimer: I'm the author of {fmt} and C++20 std::format.

std::defaultfloat doesn't reset the precision. (Don't ask me why). You could reset that to the default which is defined as 6:

std::cout << std::defaultfloat << std::setprecision(6) << f1 << " - " << f2;

Alternatively you could save the entire stream state before the operation and restore it after; see this thread for that.

std::precision specifies the precision at which cout displays, it doesn't change when you change the formating.

So when you set std::precision(2) it specifies that all formats following will display with that precision applied.

The format fixed applies precision as n being the number of places after the decimal point. The defaultfloat format applies precision as the maximum number of total digits to display.

It DOESN'T reset the precision value.

For reference: ios_base::precision

You can simply create your own std::ostream over the std::streambuf of the original std::ostream, and set your formatting on this new personal std::ostream.

#include <iostream>
#include <ostream>
#include <iomanip>

float const f1 = 3.0f, f2 = 1.5f;

void proc1() {
    std::ostream out(std::cout.rdbuf());
    out << "Inside proc1(), floats are printed like: " << std::setprecision(2) << std::fixed << f1 << " and " << f2 << '\n';
}

int main() {
    std::cout << "Inside main(), floats are printed like: " << f1 << " and " << f2 << '\n';
    proc1();
    std::cout << "Back in main(), floats are printed like: " << f1 << " and " << f2 << '\n';
}

This code will print:

Inside main(), floats are printed like: 3 and 1.5
Inside proc1(), floats are printed like: 3.00 and 1.50
Back in main(), floats are printed like: 3 and 1.5

You can try it there: http://coliru.stacked-crooked.com/a/4994c3f604b63d67

It is correct to create an std::ostream based on the std::streambuf of another one because the destructor of std::ostream doesn't touch its assigned std::streambuf. See: https://en.cppreference.com/w/cpp/io/basic_ostream/%7Ebasic_ostream

Related