2

I was figuring out the difference between log(3) and log10(3), using this code:

void testPrecisionError() {
    cout
    << log(243) / log(3) << " : "
    << int(log(243) / log(3)) << " : "
    << endl;

    cout
    << log10(243) / log10(3) << " : "
    << int(log10(243) / log10(3)) << " : ")
    << endl;
}

The output is:

5 : 4  // I think it is 4.999999 underlying
5 : 5

I found out that 4.999999 is printed out as 5.

Why doesn't C++ print it as 4.99999 like Java does?

I guess I could no more cout to convince myself that there is NO PRECISON LOSS !

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Shihao Xu
  • 1,160
  • 2
  • 10
  • 23
  • 5
    The default precision is 6. – T.C. Jul 16 '16 at 01:34
  • Why doesn't C++ print it as 4.99999 like Java?? – Shihao Xu Jul 16 '16 at 01:36
  • 4.99999 has only 5 digits of precision, not 6 like default C – phuclv Jul 16 '16 at 01:58
  • Java prints "[as many, but only as many, more digits as are needed to uniquely distinguish the argument value from adjacent values of type `double`](http://docs.oracle.com/javase/7/docs/api/java/lang/Double.html#toString(double))", so it prints [`4.999999999999999`](http://melpon.org/wandbox/permlink/DgyUgit1s2V2tGTR). – T.C. Jul 16 '16 at 02:09
  • @T.C.[Except when it doesn't](http://www.exploringbinary.com/java-doesnt-print-the-shortest-strings-that-round-trip/) – Rick Regan Jul 16 '16 at 20:02

3 Answers3

3

Because it's rounding to the nearest value of the last digit of the requested precision. The actual value is about:

4.99999999999999911182158029987

And with 6 digits of precision, that's closer to 5.000000 than 4.999999, so it shows 5. If you use setprecision(16) or higher you'll see all the 9's.

When you cast to int, it always truncates, it doesn't round to the nearest value.

As for why Java displays it as 4.999999, maybe it just discards extra digits rather than rounding.

Barmar
  • 741,623
  • 53
  • 500
  • 612
0

Welcome to the world of binary where real numbers cannot be represented correctly! double and float have a precision problem. So you need to be careful when you are comparing 2 double values etc...

For example:

  • sqrt(2) = [real value of sqrt(2)] +/- [precision error]
  • precision error depend on the type / cpu architecture you are using (double, float...)
Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92
Phong
  • 6,600
  • 4
  • 32
  • 61
0

Floating point output in iostreams is controlled by the stream's precision. The default IIRC is 6 places to the right of the decimal. If the 7th digit is a 9, it rounds the 6th digit up, and so on. In your case, 4.9999999... becomes 5.

Maximum decimal precision in IEEE 754, which is probably what you're using, is around 15 decimal places. If you set the stream's precision to 16 or so (with the setprecision manipulator), you'll see "all" the digits. But of course it's still only an approximation, because that what floating-point numbers are.

Why isn't it like Java? Two languages, two sets of rules. I'd argue that Java is wrong: if the 7th position is 9, then 4.99999 is off by 0.0000009+, whereas 5.0 is off by only 0.0000001+. Do you want more digits, or a closer approximation?

James K. Lowden
  • 7,574
  • 1
  • 16
  • 31