I have read several topics about the display of floating point numbers display in C++ and I couldn't find a satisfying answer.
My question is: how to display all the significant digits of a floating point numbers in C++ in a scientific format (mantissa/exponent) ?
The problem is that all numbers do not have the same number of significant digits in base 10.
For example a double
has 15 to 17 significant decimal digits precision, but std::numeric_limits<double>::digits10
returns 15 and consequently, for some numbers I will loose 2 extra decimal digits of precision.
Have you looked at std::max_digits10
?
From cppreference:
The value of
std::numeric_limits<T>::max_digits10
is the number of base-10 digits that are necessary to uniquely represent all distinct values of the typeT
, such as necessary for serialization/deserialization to text. This constant is meaningful for all floating-point types.
The implication of this (and is how I use it) is that the text output can be copy/pasted into another program and the number will represent the same number.
Now, I must say that my work-horse format is always right-justified %23.16E
, and I use engineering judgement for the last few digits. I like it because is is sufficient for the sign, the exponent, and sixteen digits.
-----------------------
-1.1234567812345678E+12
Now, notice that digits
of precision and decimal digits
of precision are not necessarily the same thing.
The value std::numeric_limits<double>::digits10
provides the number of decimal digits which can safely be restored, i.e., the number of decimal digits which survive a round-trip decimal->double
->decimal. Assuming more decimal digits are correct isn't helpful. If you want to faciliate the round-trip double
->decimal->double
you'd use std::numeric_limits<double>::max_digits10
.
If you want the exact values you'd use std::numeric_limits<double>::digits
but it will display numbers converted from decimal values in a funny way as they are normally rounded values. This is also the reason why max_digits10
isn't useful when presenting numbers for human consumption: the last couple of digits are normally not those expect by the human reader.
In C++20 you'll be able to use std::format
to do this:
std::cout << std::format("{}", M_PI);
Output (assuming IEEE754 double
):
3.141592653589793
The default floating-point format is the shortest decimal representation with a round-trip guarantee. The advantage of this method compared to using the precision of max_digits10
from std::numeric_limits
is that it doesn't print unnecessary digits. For example:
std::cout << std::setprecision(
std::numeric_limits<double>::max_digits10) << 0.3;
prints 0.29999999999999999
while
std::cout << std::format("{}", 0.3);
prints 0.3
(godbolt).
In the meantime you can use the {fmt} library, std::format
is based on. {fmt} also provides the print
function that makes this even easier and more efficient (godbolt):
fmt::print("{}", M_PI);
Disclaimer: I'm the author of {fmt} and C++20 std::format
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With