0

From what I understand, the famous

 (0.1 + 0.2) !== 0.3

gotcha is not actually Javascript's fault. Thats just the way the IEEE 754 works. A similar output happens in Python, which also follows the IEEE 754 rules.

Then how come this particular example works as expected in C, sometimes. If I do a direct comparison

printf("%d\n", (0.1+0.2) == 0.3);

I get the (un?)expected output 0, but if I put the values into variables or print them out, I get properly rounded answers.

C Runnable Example

Is the C implementation of IEEE 754 doing something extra? Or is it something completely else that I am missing.

Update

The code sample I posted was broken due to a typo. Try this one Fixed C Runnable Example

But the original Question still remains.

double d1, d2, d3;
d1 = 0.1;    d2 = 0.2;    d3 = d1 + d2;
printf ("%d\n", ((((double)0.1)+((double)0.2)) == ((double)d3)));
printf ("%.17f\n", d1+d2);
printf ("%d\n", ((d1+d2) == d3));

The output is

1
0.30000000000000004
1

The rephrased question now is:

  1. Why (and when, and how) is the C compiler taking the liberty to say that

    0.3 == 0.30000000000000004

  2. Given all facts, isn't it true that the C implementation is broken, rather than Javascripts'?

Manav
  • 10,094
  • 6
  • 44
  • 51
  • 3
    in your code sample you never actually print any numbers that aren't integers. – Alnitak Jul 03 '12 at 09:45
  • You question doesn't really have anything to do with JavaScript. It has to do with C and handling of doubles, where sometimes you get one result, and other times you get a different result. (My guess would be that sometimes, the preprocessor is doing the math, and so what the *compiler* sees is `printf("%d\n", 0.3 == 0.3);`, but it's just a guess.) – T.J. Crowder Jul 03 '12 at 09:45
  • 1
    @Manav: Even when you also provide a link, always include the relevant code (and output) **in the question itself**. The code you currently have in the question is *different* from the code you've linked to, and links can rot. More: http://meta.stackexchange.com/questions/118392/add-stack-overfow-faq-entry-or-similar-for-putting-code-in-the-question – T.J. Crowder Jul 03 '12 at 09:48
  • @Alnitak So? Does that matter? – Manav Jul 03 '12 at 09:49
  • @T.J.Crowder look at the link again - `d1`, `d2` and `d3` are all whole numbers. The only line using fractions is the second one, with the comparison in it. – Alnitak Jul 03 '12 at 09:51
  • @Alnitak: Ah, you mean in the link. Sure enough, s/he's forgotten the `0.` in front of the `1`, `2`, and `3` when setting up the `d*` vars! – T.J. Crowder Jul 03 '12 at 09:52
  • @Manav: *"So? Does that matter?"* Of course `1` vs. `0.1` matters, when you're exploring the intricacies of floating point imprecision. Note how with the fix, things become predictable again: http://codepad.org/oDFjMY8s – T.J. Crowder Jul 03 '12 at 09:53
  • @Manav in particular, all whole numbers (within range) are _exactly_ representable in IEEE 754 so don't suffer this problem. 1.0 + 2.0 really does == 3.0 in floating point, but 0.1 + 0.2 does not == 0.3 – Alnitak Jul 03 '12 at 09:55
  • @Alnitak Sorry for the confusion. See my update. – Manav Jul 03 '12 at 10:01
  • 1
    please take note that GCC is "differently broken" than MSVC. Check out how different compiler give different results: http://stackoverflow.com/questions/10912128/printing-the-integral-part-of-a-floating-point-number/10912657#10912657 – Agent_L Jul 03 '12 at 10:03

3 Answers3

4

Why (and when, and how) is the C compiler taking the liberty to say that

    0.3 == 0.30000000000000004

Given all facts, isn't it true that the C implementation is broken, rather than Javascripts'?

It isn't.

The output given is from this code:

printf ("%d\n", ((((double)0.1)+((double)0.2)) == ((double)d3)));

but you wrote:

d1 = 0.1;    d2 = 0.2;    d3 = d1 + d2;

so d3 is not 0.3, it's 0.30000000000000004

Alnitak
  • 334,560
  • 70
  • 407
  • 495
1
`printf("%d\n", (0.1+0.2) == 0.3);`

These are DOUBLEs not FLOATs.

Do:

printf("%d\n", (0.1+0.2) == 0.3);
printf("%d\n", (0.1f+0.2f) == 0.3f);

and voila!

http://codepad.org/VF9svjxY

Output:
0
1

Check out this question. It's about smth else, but ppl using GCC got different results than ppl with MSVC. printing the integral part of a floating point number

Community
  • 1
  • 1
Agent_L
  • 4,960
  • 28
  • 30
  • 1
    MSVC uses SSE FPU in 64-bit mode and x87 FPU in 32-bit mode. The latter stores all intermediate results with 80-bit precision. It is possible to get around this with intermediate stores and reloads. – Hristo Iliev Jul 03 '12 at 12:10
0

Your example code uses 1, 2 and (1+2), which are all exactly representable in double precision floating point. 0.1 on the other hand is NOT exactly representable in floating point and thus you get an approximation to this number. When adding approximately 0.1 to approximately 0.2 you will get approximately 0.3, but whether that's going to be EXACTLY the same approximation that a compiler would choose when representing 0.3 who can tell.

The representation is using binary. Which means it uses 1/2, 1/4, 1/8, 1/16, 1/32 (and so on to a number of precision ....). This means that 0.5, 0.25 etc are exactly able to be represented. Numbers that aren't an exact sum of binary fractions can be approximated very closely.

Solution: don't compare floating point numbers to each other. Compare their difference to some small number that you don't care about.

#define EPSILON 0.000001
printf("%d", fabs((0.1+0.2) - 0.3 ) < EPSILON );

I'm not sure why the C code works and the python/javascript doesn't. It's magic. But hopefully this answers your question anyway.

dave
  • 4,812
  • 4
  • 25
  • 38
  • 1
    I want to know about this 'magic' that you refer to in the last line of your answer. – Manav Jul 03 '12 at 10:02
  • I answered before his update to a new code sample. The previous one was broken and didn't compare decimals at all. So I didn't know why he thought his C code worked and javascript didn't (especially as there was no javascript code sample). So I explained how floats are represented and why there isn't a precise answer in arithmetic and thus why one implementation might work and another not. Thus it's "magic" as to whether comparing floats for equality will work or not. ie don't do it. – dave Jul 30 '12 at 06:15