374

In my earlier question I was printing a double using cout that got rounded when I wasn't expecting it. How can I make cout print a double using full precision?

vitaut
  • 37,224
  • 19
  • 144
  • 248
Jason Punyon
  • 37,168
  • 13
  • 93
  • 118
  • Sadly most of the answers below are incorrect. I recommend checking out https://stackoverflow.com/questions/19610161/full-precision-display-of-floating-point-numbers-in-c instead. – vitaut Dec 17 '20 at 19:23
  • 1
    @vitaut I don't recommend marking highly popular questions as duplicates of much smaller ones. Your answer will eventually reach the top here. Who knows, in 10 years, there will be an even better method (unlikely in this case). Then what do we do? Close the second and open a third? It would be messy. This one has the Google pagerank, so let's make the right answer go up here. Underlying problem is that SO's answer sorting algorithms are naive, but they just don't care about fixing it. – Ciro Santilli新疆棉花TRUMP BAN BAD Jan 09 '21 at 08:37
  • Actually the other question is more recent (duplicate), so it should be https://stackoverflow.com/questions/19610161/full-precision-display-of-floating-point-numbers-in-c that should be closed and this one (original) that should be reopened. – Antonin GAVREL Feb 27 '21 at 06:50

16 Answers16

440

You can set the precision directly on std::cout and use the std::fixed format specifier.

double d = 3.14159265358979;
cout.precision(17);
cout << "Pi: " << fixed << d << endl;

You can #include <limits> to get the maximum precision of a float or double.

#include <limits>

typedef std::numeric_limits< double > dbl;

double d = 3.14159265358979;
cout.precision(dbl::max_digits10);
cout << "Pi: " << d << endl;
Bill the Lizard
  • 369,957
  • 201
  • 546
  • 842
  • 48
    Why do you explicitly advise to use `fixed`? With `double h = 6.62606957e-34;`, `fixed` gives me `0.000000000000000` and `scientific` outputs `6.626069570000000e-34`. – Arthur Jan 09 '12 at 17:58
  • 36
    The precision needs to be 17 (or std::numeric_limits::digits10 + 2) because 2 extra digits are needed when converting from decimal back to the binary representation to ensure the value is rounded to the same original value. Here is a paper with some details: http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html – Mike Fisher Oct 28 '13 at 09:16
  • 9
    Is the really the right answer? When I manually use a high number, I can print out as many as 51 digits of approximated e, but with `cout.precision(numeric_limits::digits10 + 2);` I only get 16.... – Assimilater Sep 04 '14 at 22:07
  • 6
    For those looking where it mentions 17 digits in the paper @MikeFisher cited, it's under Theorem 15. – Emile Cormier Jan 11 '15 at 21:23
  • 16
    @MikeFisher You're right, [C++11 introduces `max_digits10`](http://www2.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1822.pdf) to denote the same. Fixed the answer to reflect this. – legends2k Aug 24 '15 at 07:47
  • 2
    `max_digits10` might be useful for setting the number of figures displayed in scientific notation; for fixed it only works for values with magnitude near 1. – Ben Voigt Nov 15 '15 at 21:24
  • 1
    But what is the reason behind? why cout not print value as it is? – Asif Mushtaq Jan 16 '16 at 16:16
  • @Ben, I agree with you. max_digits10 gives the maximum number of digits before and after the decimal point. set_precision() with fixed specifier sets the number of digits only after the decimal point. – Daniel Laügt Jan 17 '16 at 22:46
  • 1
    @DanielLaügt am I right in thinking then that the currently posted solution should work, since if max_digits10 denotes the total number of digits period then set_precision with that many digits should only be overkill, and no precision should be lost? – Joseph Garvin Apr 13 '17 at 23:45
  • @MikeFisher Disagree about "or std::numeric_limits::digits10 + 2". Depending on various FP attributes, _in general_, the +2 needs to be as high as +3. Note +3 applies commonly with `float`. – chux - Reinstate Monica Sep 12 '18 at 13:25
  • 2
    @chux indeed, with float we have 6 vs 9 digits. But also with `long double` on x87 (with full precision, e.g. in GCC) we have 18 vs 21 digits, a well as with `float128` (IEEE754 `binary128`): 33 vs 36 digits. So it's the `double` who is outlier with its 15 vs 17 digits min and max. – Ruslan May 27 '19 at 17:33
  • I see people using in our code set_precision(18) for double. Is this really meaning full? Shouldn't we use set_precision(17)? – stephanmg Feb 11 '20 at 00:52
  • 1
    @Assimilater Most of those are just artefacts of the particular negative power of two. Here's a simplified example: Imagine you had a super-low precision type with only three binary places and no exponent, so it could only represent 0, 1/8, 2/8, ..., 7/8. Then converting 0.1 to it and back would give you "0.125" so it looks like 3 decimal places of precision, but really there's only 1 decimal place of actual information. – Arthur Tacca Jun 16 '20 at 08:57
  • @ass No, this is not the correct answer. It confuses two concepts: *"full precision"* and *"no loss of information"*. Displaying `max_digits10` digits guarantees that converting that decimal back to a floating point value will result in the same binary representation, so there is no loss of information. That's far from full precision, though. A floating point value represented in base 10 will always end in a final decimal of either `0` or `5`. The [proposed solution](https://godbolt.org/z/vZCLTq)'s output ends in `9`. – IInspectable Jun 24 '20 at 22:11
80

Use std::setprecision:

std::cout << std::setprecision (15) << 3.14159265358979 << std::endl;
Campa
  • 3,502
  • 3
  • 30
  • 34
Paul Beckingham
  • 13,460
  • 5
  • 30
  • 67
27

Here is what I would use:

std::cout << std::setprecision (std::numeric_limits<double>::digits10 + 1)
          << 3.14159265358979
          << std::endl;

Basically the limits package has traits for all the build in types.
One of the traits for floating point numbers (float/double/long double) is the digits10 attribute. This defines the accuracy (I forget the exact terminology) of a floating point number in base 10.

See: http://www.cplusplus.com/reference/std/limits/numeric_limits.html
For details about other attributes.

Martin York
  • 234,851
  • 74
  • 306
  • 532
13

The iostreams way is kind of clunky. I prefer using boost::lexical_cast because it calculates the right precision for me. And it's fast, too.

#include <string>
#include <boost/lexical_cast.hpp>

using boost::lexical_cast;
using std::string;

double d = 3.14159265358979;
cout << "Pi: " << lexical_cast<string>(d) << endl;

Output:

Pi: 3.14159265358979

Timothy003
  • 2,289
  • 4
  • 27
  • 33
  • The boost documentation says "For numerics that have a corresponding specialization of std::numeric_limits, the current version now chooses a precision to match". This seems like the easiest way to get the max precision. (http://www.boost.org/doc/libs/1_58_0/doc/html/boost_lexical_cast/changes.html) – JDiMatteo May 15 '15 at 21:34
11

By full precision, I assume mean enough precision to show the best approximation to the intended value, but it should be pointed out that double is stored using base 2 representation and base 2 can't represent something as trivial as 1.1 exactly. The only way to get the full-full precision of the actual double (with NO ROUND OFF ERROR) is to print out the binary bits (or hex nybbles).

One way of doing that is using a union to type-pun the double to a integer and then printing the integer, since integers do not suffer from truncation or round-off issues. (Type punning like this is not supported by the C++ standard, but it is supported in C. However, most C++ compilers will probably print out the correct value anyways. I think g++ supports this.)

union {
    double d;
    uint64_t u64;
} x;
x.d = 1.1;
std::cout << std::hex << x.u64;

This will give you the 100% accurate precision of the double... and be utterly unreadable because humans can't read IEEE double format ! Wikipedia has a good write up on how to interpret the binary bits.

In newer C++, you can do

std::cout << std::hexfloat << 1.1;
Mark Lakata
  • 18,024
  • 5
  • 88
  • 112
11

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 the setprecision I/O manipulator is that it doesn't print unnecessary digits.

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.

vitaut
  • 37,224
  • 19
  • 144
  • 248
10

Here is how to display a double with full precision:

double d = 100.0000000000005;
int precision = std::numeric_limits<double>::max_digits10;
std::cout << std::setprecision(precision) << d << std::endl;

This displays:

100.0000000000005


max_digits10 is the number of digits that are necessary to uniquely represent all distinct double values. max_digits10 represents the number of digits before and after the decimal point.


Don't use set_precision(max_digits10) with std::fixed.
On fixed notation, set_precision() sets the number of digits only after the decimal point. This is incorrect as max_digits10 represents the number of digits before and after the decimal point.

double d = 100.0000000000005;
int precision = std::numeric_limits<double>::max_digits10;
std::cout << std::fixed << std::setprecision(precision) << d << std::endl;

This displays incorrect result:

100.00000000000049738

Note: Header files required

#include <iomanip>
#include <limits>
Daniel Laügt
  • 919
  • 1
  • 10
  • 17
  • 5
    This happens because `100.0000000000005` isn't being represented exactly as a `double`. (It might seem like it should, but it doesn't, because it gets [normalised](https://en.wikipedia.org/wiki/IEEE_754-1985), i.e. its binary representation). To see this, try: `100.0000000000005 - 100`. We get `4.973799150320701e-13`. – Evgeni Sergeev Sep 08 '17 at 12:12
10

How do I print a double value with full precision using cout?

Use hexfloat or
use scientific and set the precision

std::cout.precision(std::numeric_limits<double>::max_digits10 - 1);
std::cout << std::scientific <<  1.0/7.0 << '\n';

// C++11 Typical output
1.4285714285714285e-01

Too many answers address only one of 1) base 2) fixed/scientific layout or 3) precision. Too many answers with precision do not provide the proper value needed. Hence this answer to a old question.

  1. What base?

A double is certainly encoded using base 2. A direct approach with C++11 is to print using std::hexfloat.
If a non-decimal output is acceptable, we are done.

std::cout << "hexfloat: " << std::hexfloat << exp (-100) << '\n';
std::cout << "hexfloat: " << std::hexfloat << exp (+100) << '\n';
// output
hexfloat: 0x1.a8c1f14e2af5dp-145
hexfloat: 0x1.3494a9b171bf5p+144

  1. Otherwise: fixed or scientific?

A double is a floating point type, not fixed point.

Do not use std::fixed as that fails to print small double as anything but 0.000...000. For large double, it prints many digits, perhaps hundreds of questionable informativeness.

std::cout << "std::fixed: " << std::fixed << exp (-100) << '\n';
std::cout << "std::fixed: " << std::fixed << exp (+100) << '\n';
// output
std::fixed: 0.000000
std::fixed: 26881171418161356094253400435962903554686976.000000 

To print with full precision, first use std::scientific which will "write floating-point values in scientific notation". Notice the default of 6 digits after the decimal point, an insufficient amount, is handled in the next point.

std::cout << "std::scientific: " << std::scientific << exp (-100) << '\n';  
std::cout << "std::scientific: " << std::scientific << exp (+100) << '\n';
// output
std::scientific: 3.720076e-44
std::scientific: 2.688117e+43

  1. How much precision (how many total digits)?

A double encoded using the binary base 2 encodes the same precision between various powers of 2. This is often 53 bits.

[1.0...2.0) there are 253 different double,
[2.0...4.0) there are 253 different double,
[4.0...8.0) there are 253 different double,
[8.0...10.0) there are 2/8 * 253 different double.

Yet if code prints in decimal with N significant digits, the number of combinations [1.0...10.0) is 9/10 * 10N.

Whatever N (precision) is chosen, there will not be a one-to-one mapping between double and decimal text. If a fixed N is chosen, sometimes it will be slightly more or less than truly needed for certain double values. We could error on too few (a) below) or too many (b) below).

3 candidate N:

a) Use an N so when converting from text-double-text we arrive at the same text for all double.

std::cout << dbl::digits10 << '\n';
// Typical output
15

b) Use an N so when converting from double-text-double we arrive at the same double for all double.

// C++11
std::cout << dbl::max_digits10 << '\n';
// Typical output
17

When max_digits10 is not available, note that due to base 2 and base 10 attributes, digits10 + 2 <= max_digits10 <= digits10 + 3, we can use digits10 + 3 to insure enough decimal digits are printed.

c) Use an N that varies with the value.

This can be useful when code wants to display minimal text (N == 1) or the exact value of a double (N == 1000-ish in the case of denorm_min). Yet since this is "work" and not likely OP's goal, it will be set aside.


It is usually b) that is used to "print a double value with full precision". Some applications may prefer a) to error on not providing too much information.

With .scientific, .precision() sets the number of digits to print after the decimal point, so 1 + .precision() digits are printed. Code needs max_digits10 total digits so .precision() is called with a max_digits10 - 1.

typedef std::numeric_limits< double > dbl;
std::cout.precision(dbl::max_digits10 - 1);
std::cout << std::scientific <<  exp (-100) << '\n';
std::cout << std::scientific <<  exp (+100) << '\n';
// Typical output
3.7200759760208361e-44
2.6881171418161356e+43
//1234567890123456  17 total digits

Similar C question

chux - Reinstate Monica
  • 113,725
  • 11
  • 107
  • 213
  • Great answer! A few remarks though: You're right that `precision()` sets the number of decimal places for scientific mode. Without specifying `scientific`, it sets the total number of digits, excluding the exponent. You might still end up with scientific output, depending on your number value, but then you might also get less digits than you specified. Example: `cout.precision(3); cout << 1.7976931348623158e+308; // "1.8e+308"` Results for `printf` may be different. Confusing stuff one should be aware off. – Simpleton Mar 04 '20 at 08:46
  • For posterity, here's the required buffer length for guaranteed exact string representation of all double numbers in scientific mode using printf: `char buf[DBL_DECIMAL_DIG + 3 + 5]; sprintf(buf, "%.*g", DBL_DECIMAL_DIG, d);` The extra characters are for: sign, decimal point, trailing zero, e[+|-], 3 digits for the exponent (DBL_MAX_10_EXP = 308). Hence the total number of required characters is 25. – Simpleton Mar 04 '20 at 08:56
  • Can't edit my first comment, so here we go again: Another issue with scientific mode is that it might decide to not use exponential output, it even might decide to not use floating point output at all. That is, it will output 1.0 as "1", which might be a problem in a serialization/deserialization context. You can force it to output a decimal point by using "%#.*g", but this has the drawback that it adds a number of trailing zeros, which it doesn't without the #... – Simpleton Mar 05 '20 at 10:13
  • *"Whatever N (precision) is chosen, there will not be a one-to-one mapping between double and decimal text."* - That's incorrect. **Any** floating point value has an exact, finite representation in decimal. The opposite isn't true, though. There is no finite representation for the decimal value `0.1` as a floating point value, for example. – IInspectable Jun 23 '20 at 22:01
2
printf("%.12f", M_PI);

%.12f means floating point, with precision of 12 digits.

Maister
  • 4,712
  • 1
  • 29
  • 32
2

IEEE 754 floating point values are stored using base 2 representation. Any base 2 number can be represented as a decimal (base 10) to full precision. None of the proposed answers, however, do. They all truncate the decimal value.

This seems to be due to a misinterpretation of what std::numeric_limits<T>::max_digits10 represents:

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 type T.

In other words: It's the (worst-case) number of digits required to output if you want to roundtrip from binary to decimal to binary, without losing any information. If you output at least max_digits10 decimals and reconstruct a floating point value, you are guaranteed to get the exact same binary representation you started with.

What's important: max_digits10 in general neither yields the shortest decimal, nor is it sufficient to represent the full precision. I'm not aware of a constant in the C++ Standard Library that encodes the maximum number of decimal digits required to contain the full precision of a floating point value. I believe it's something like 767 for doubles1. One way to output a floating point value with full precision would be to use a sufficiently large value for the precision, like so2, and have the library strip any trailing zeros:

#include <iostream>

int main() {
    double d = 0.1;
    std::cout.precision(767);
    std::cout << "d = " << d << std::endl;
}

This produces the following output, that contains the full precision:

d = 0.1000000000000000055511151231257827021181583404541015625

Note that this has significantly more decimals than max_digits10 would suggest.


While that answers the question that was asked, a far more common goal would be to get the shortest decimal representation of any given floating point value, that retains all information. Again, I'm not aware of any way to instruct the Standard I/O library to output that value. Starting with C++17 the possibility to do that conversion has finally arrived in C++ in the form of std::to_chars. By default, it produces the shortest decimal representation of any given floating point value that retains the entire information.

Its interface is a bit clunky, and you'd probably want to wrap this up into a function template that returns something you can output to std::cout (like a std::string), e.g.

#include <charconv>
#include <array>
#include <string>
#include <system_error>

#include <iostream>
#include <cmath>

template<typename T>
std::string to_string(T value)
{
    // 24 characters is the longest decimal representation of any double value
    std::array<char, 24> buffer {};
    auto const res { std::to_chars(buffer.data(), buffer.data() + buffer.size(), value) };
    if (res.ec == std::errc {})
    {
        // Success
        return std::string(buffer.data(), res.ptr);
    }

    // Error
    return { "FAILED!" };
}

int main()
{
    auto value { 0.1f };
    std::cout << to_string(value) << std::endl;
    value = std::nextafter(value, INFINITY);
    std::cout << to_string(value) << std::endl;
    value = std::nextafter(value, INFINITY);
    std::cout << to_string(value) << std::endl;
}

This would print out (using Microsoft's C++ Standard Library):

0.1
0.10000001
0.10000002

1 From Stephan T. Lavavej's CppCon 2019 talk titled Floating-Point <charconv>: Making Your Code 10x Faster With C++17's Final Boss. (The entire talk is worth watching.)

2 This would also require using a combination of scientific and fixed, whichever is shorter. I'm not aware of a way to set this mode using the C++ Standard I/O library.

IInspectable
  • 35,521
  • 8
  • 69
  • 148
  • @chu That assumes that the smallest representable value is also the one with the longest sequence of digits in decimal. That sounds plausible, but plausibility is not quite where floating point values are at home. Have you tried to use [nextafter](https://en.cppreference.com/w/c/numeric/math/nextafter) to see, if the lengths increase in the vicinity of `DBL_TRUE_MIN`? – IInspectable Jun 23 '20 at 21:25
  • @chu Ah, true, `DBL_TRUE_MIN` only has its least significant bit set in the mantissa. Hadn't thought of that. Still, I'd need to see a mathematical proof to understand, why that would result in the longest decimal sequence. – IInspectable Jun 23 '20 at 21:37
  • Note: "One way to output a floating point value with full precision would be to use a sufficiently large value for the precision," --> A library compliant to IEEE 754 need only print the correctly rounded value to `long double::max_digits10` + 3 significant digits. We might not get full precision. – chux - Reinstate Monica Jun 23 '20 at 21:37
  • "I'd need to see a mathematical proof to understand" --> sounds like a good question on some site - and a bit of work to fulfill - too much for a quick comment. – chux - Reinstate Monica Jun 23 '20 at 21:39
  • Yes `DBL_MIN - DBL_TRUE_MIN` took 767 significant digits. – chux - Reinstate Monica Jun 23 '20 at 23:10
  • @chu *"A library compliant to IEEE 754 need only print the correctly rounded value to `long double::max_digits10` + 3 significant digits."* - I wasn't able to find this requirement in the C++ Standard text. Is this incorporated from C, and if so, do you happen to know where I can find that? – IInspectable Jun 25 '20 at 13:38
  • IInspectable, the spec is a IEEE 754 one (sec 5.12), not a C++ one. C++ may follow IEEE754 to various degrees of compliance. [limit, H, shall be such that H ≥ M+3](https://stackoverflow.com/a/11087221/2410359) – chux - Reinstate Monica Jun 25 '20 at 16:06
2

C++20 std::format

This great new C++ library feature has the advantage of not affecting the state of std::cout as std::setprecision does:

#include <format>
#include <string>

int main() {
    std::cout << std::format("{:.2} {:.3}\n", 3.1415, 3.1415);
}

Expected output:

3.14 3.145

The as mentioned at https://stackoverflow.com/a/65329803/895245 not if you don't pass the precision explicitly it prints the shortest decimal representation with a round-trip guarantee. TODO understand in more detail how it compares to: dbl::max_digits10 as shown at https://stackoverflow.com/a/554134/895245 with {:.{}}:

#include <format>
#include <limits>
#include <string>

int main() {
    std::cout << std::format("{:.{}}\n",
        3.1415926535897932384626433, dbl::max_digits10);
}

See also:

1

Most portably...

#include <limits>

using std::numeric_limits;

    ...
    cout.precision(numeric_limits<double>::digits10 + 1);
    cout << d;
1

In this question there is a description on how to convert a double to string losselessly (in Octave, but it can be easily reproduced in C++). De idea is to have a short human readable description of the float and a losseless description in hexa form, for instance: pi -> 3.14{54442d18400921fb}.

0

This will show the value up to two decimal places after the dot.

#include <iostream>
#include <iomanip>

double d = 2.0;
int n = 2;
cout << fixed << setprecision(n) << d;

See here: Fixed-point notation

std::fixed

Use fixed floating-point notation Sets the floatfield format flag for the str stream to fixed.

When floatfield is set to fixed, floating-point values are written using fixed-point notation: the value is represented with exactly as many digits in the decimal part as specified by the precision field (precision) and with no exponent part.

std::setprecision

Set decimal precision Sets the decimal precision to be used to format floating-point values on output operations.

If you're familiar with the IEEE standard for representing the floating-points, you would know that it is impossible to show floating-points with full-precision out of the scope of the standard, that is to say, it will always result in a rounding of the real value.

You need to first check whether the value is within the scope, if yes, then use:

cout << defaultfloat << d ;

std::defaultfloat

Use default floating-point notation Sets the floatfield format flag for the str stream to defaultfloat.

When floatfield is set to defaultfloat, floating-point values are written using the default notation: the representation uses as many meaningful digits as needed up to the stream's decimal precision (precision), counting both the digits before and after the decimal point (if any).

That is also the default behavior of cout, which means you don't use it explicitly.

Yushan ZHANG
  • 345
  • 3
  • 15
  • It should be setprecision and not setprecison. Note: the edition proposal is blocked because it contains less than 6 characters! – Vincent Vidal Nov 26 '20 at 09:10
0

Here is a function that works for any floating-point type, not just double, and also puts the stream back the way it was found afterwards. Unfortunately it won't interact well with threads, but that's the nature of iostreams. You'll need these includes at the start of your file:

#include <limits>
#include <iostream>

Here's the function, you could it in a header file if you use it a lot:

template <class T>
void printVal(std::ostream& os, T val)
{
    auto oldFlags = os.flags();
    auto oldPrecision = os.precision();

    os.flags(oldFlags & ~std::ios_base::floatfield);
    os.precision(std::numeric_limits<T>::digits10);
    os << val;
    
    os.flags(oldFlags);
    os.precision(oldPrecision);
}

Use it like this:

double d = foo();
float f = bar();
printVal(std::cout, d);
printVal(std::cout, f);

If you want to be able to use the normal insertion << operator, you can use this extra wrapper code:

template <class T>
struct PrintValWrapper { T val; };
template <class T>
std::ostream& operator<<(std::ostream& os, PrintValWrapper<T> pvw) {
    printVal(os, pvw.val);
    return os;
}
template <class T>
PrintValWrapper<T> printIt(T val) {
    return PrintValWrapper<T>{val};
}

Now you can use it like this:

double d = foo();
float f = bar();
std::cout << "The values are: " << printIt(d) << ", " << printIt(f) << '\n';
Arthur Tacca
  • 6,565
  • 1
  • 27
  • 42
-1

With ostream::precision(int)

cout.precision( numeric_limits<double>::digits10 + 1);
cout << M_PI << ", " << M_E << endl;

will yield

3.141592653589793, 2.718281828459045

Why you have to say "+1" I have no clue, but the extra digit you get out of it is correct.

Jann
  • 123
  • 5
  • 3
    numeric_limits::digits10 equals to 2. Because it can contain any decimal number of two digits 0..99. It can also contain 255.. but not 256, 257... 300 etc. this is why digits10 is not 3! I think "+1" is added to overcome something like this. – Dmitriy Yurchenko Apr 24 '13 at 23:42