4

Why does std::cout << 1.00000001; print 1 to the console? It Works fine with 1.0001, Its only after it exceeds a certain precision when it stops printing it properly.

These numbers are hard coded, so this question is not a duplicate. In that question, an irrational number was produced because two floating point numbers were added, which means the numbers could not be stored properly, but in my case the numbers are hard coded, so what is the reason for not being able to print (or store maybe) a float explicitly initialised as 1.00000001?. Is it just cout failing to print the value or is it really an int?

Consider the following program

int main()
{
    float num = 1.0000001f;
    float num2 = num * 2;
    std::cout << num;
    std::cout << num2;
}

num2 prints 2 but the complier does not give a warning about conversion from float to int in line 2, so I think that num must be a float. Does that mean it's just a problem with cout? Am I safe to assume that internally num is actually 1.0000001f even though it prints 1 to the console?

My complier is visual studio 2019's inbuilt one.

  • 2
    This *is* in fact the exact same problem. 1.00000001f is strictly the same as 1.f. – spectras Dec 26 '20 at 00:20
  • @spectras so that 1 at the end was just lost? –  Dec 26 '20 at 00:21
  • 4
    Yes. A float has a limited precision. Try to play a bit with this converter: https://www.h-schmidt.net/FloatConverter/IEEE754.html to get a picture of how it works. – spectras Dec 26 '20 at 00:22
  • @spectras Ok thanks. I tried converting it from float to long double and it seems to handle high precision numbers properly now. But I would assume that float only drops the precision it cant store. Why would it drop all of it when it exceeds it's limit? –  Dec 26 '20 at 00:26
  • 1
    `1.0000001f` is the same value as `1.0f` (to be more precise: it is implementation-defined whether the notation `1.0000001f` will give you the floating number 1.0 or 1.00000011920928955078125. Both are valid choices by the compiler as those are the 2 closest floats to 1.0000001). – spectras Dec 26 '20 at 00:32
  • _@user14859499_ I have to agree with @spectras, it's exactly the problem that was described and answered in the dupe. It doesn't matter if the numbers were calculated or hard coded. You can just try to build a serial sum of the binary fractions (1 + 1/2 + 1/2^2 + ... + 1/2^n) that gives you an exact result for 1.0000001. Plain math explains why it's not possible to represent this number as a sum of binary fractions. – πάντα ῥεῖ Dec 26 '20 at 00:50

2 Answers2

4

Summarizing my comments:

  • The number 1.0000001 cannot be represented by a float.
  • The compiler will pick a float value.
  • It can round however it wants (up, down or closest), that's implementation-defined.

So if you play a bit with this converter, you can see that after 1, the next float values are:

  • 1
  • 1.00000011920928955078125
  • 1.0000002384185791015625
  • 1.00000035762786865234375
  • 1.000000476837158203125
  • ...

1.0000001 falls in between the first two, so your compiler can choose either. In your case it seems your compiler picked 1.

(also for printing operations, cout operations will truncate digits after a defined precision, so it does not show the full numbers I put above - that precision defaults to 6 digits).

spectras
  • 13,105
  • 2
  • 31
  • 53
3

The default precision I believe is 6 digits for you, but they are all zeroes. So they don't print.

#include <iostream>
#include <iomanip>

int main()
{
    std::cout << std::setprecision(10);

    // this is what you had
    float f1 = 1.0000001f;
    float f2 = f1 * 2;
    std::cout << f1 << std::endl;
    std::cout << f2 << std::endl;

    // any more zeroes and it would have been idistinguishable from 1.0
    f1 = 1.00000001f;
    f2 = f1 * 2;
    std::cout << f1 << std::endl;
    std::cout << f2 << std::endl;
}

1.000000119
2.000000238
1
2

Kenny Ostrom
  • 5,639
  • 2
  • 21
  • 30
  • Your compiler is still free to give you 1 2 1 2 as an output, that's implementation defined. Upvoted for mentioning the rendering precision :) – spectras Dec 26 '20 at 00:54