0.2 + 0.1 = 0.30000000000000004

This post is part of a series about cross-compiling ActionScript to JavaScript. In order to illustrate some fundamental problems of cross-compiling ActionScript to JavaScript I would like to start with this simple JavaScript expression:

alert( 0.2 + 0.1 );

It might surprise you that Chrome, Safari, Firefox, and IE8 all report 0.30000000000000004. The bad news is that the result is incorrect, the good news is that we get an incorrect result consistently across all most popular browsers.

This astonishing result should raise some questions:

  • Is this a bug?
  • If so, why don’t they fix it in the browsers?
  • If not, is this defined in the JavaScript language specification, ECMA-262?

But even worse:

  • What if ActionScript correctly returned 0.3 for “0.2 + 0.1”?

Then we would be in serious trouble. Let me walk you through this…

 

Should the cross-compiler leave the expression “0.2 + 0.1” unchanged when translating to JavaScript?

Then the result would not be 0.3 when run in the browser and the internal consistency of the generated JavaScript code might be compromised, because our ActionScript code assumed 0.2 + 0.1 to be 0.3.

 

Should the cross-compiler inject code that makes sure that the result will be 0.3 in JavaScript?

How? For example like this:

alert((0.2*10 + 0.1*10) / 10);

That doesn’t sound like a good idea. Any modification like the code above, or injecting Math.round() etc. would introduce tons of unwanted side-effects.

 

Should the cross-compiler try to evaluate values to constants at compile time, thus avoiding the problem altogether?

Like this:

alert( 0.3 );

Be warned, I am taking you for a ride. The code above is not a good solution for several reasons. For one, while constant folding may avoid the problem in this case, you could easily construct cases where the cross-compiler cannot evaluate values to constants at compile-time:

function addNumbers( left, right )
{
   return left + right;
}
alert( addNumbers(0.2, 0.1) );

The main reason why injecting 0.3 is not a good idea is that it is not necessary. In fact, constant folding would create unwanted results in this case. If you think this is crazy-talk, read on…

 

Happy End

So, are we in trouble with cross-compiling “0.2 + 0.1” from ActionScript to JavaScript, or not? What does ActionScript return?

0.30000000000000004

Lucky me! That’s all we need to know: We consistently get the same wrong result in ActionScript and JavaScript. In other words the cross-compiler should leave numeric expressions like “0.2 + 0.1” unchanged.

 

Epilog

The cross-compiler’s most important goal is preserving the internal consistency of the input code in the target code. ActionScript code should ideally yield the same results when compiled to SWF and run in the FlashPlayer as code that is cross-compiled to JavaScript and run in the browser. Whether the results are correct, or not, does not matter. Whether the results differ at runtime between source and target code does matter.

In conclusion,

  1. A cross-compiler needs to preserve the internal consistency of the input code in the generated code.
  2. A cross-compiler needs to remove ambiguities that may result in generated code that yields different runtime behavior.
  3. Even a well specified language like JavaScript may contain areas that are underspecified.
  4. Sometimes it is better to be lucky than smart.

 

(BTW, if you are interested in JavaScript oddities like “0.2 + 0.1” I recommend watching the Crockford on JavaScript talks and reading wtfjs.com).

 

4 Responses to 0.2 + 0.1 = 0.30000000000000004

  1. Pedro Varela says:

    I hope I have misunderstood this message, but you are saying that javascript shows the result 0.30000004 when the sum in done.

    Actionscript do the same… Alert.show( (0.2+0.1).toString());

    http://dl.dropbox.com/u/592105/02%2B01%3D0.300000004.PNG

    I didn’t get the point of this message. Saludos!

  2. Bernd Paradies says:

    Yes, the result is 0.30000000000000004 for 0.2 + 0.1 in ActionScript and JavaScript.
    The punch line is that the result being wrong is actually not a problem for the cross-compiler, because the result is wrong in AS3 and JS. If the result is the same in source and target language then the expression can be translated without modifications, i.e.:

    ActionScript source: var num = 0.2 + 0.1;
    Generated JavaScript: var num = 0.2 + 0.1;

    That was my main point: the cross-compiler needs to preserve the internal consistency of the input code in the generated code. If you get 0.30000000000000004 in AS3 we should aim to get that same result in JS.

    That the result itself is wrong is tragic. But that’s a different topic.
    Does that make it more clear?

  3. Maybe I’ve been a programmer for too long but I don’t see 0.1 + 0.2 = 0.30000000000000004 as wrong. Just saying.

  4. guest says:

    Don’t get me wrong. What you are working on is pretty exciting in terms of its potential, if done right and if it works. While I am eagerly looking forward to hearing all the nitty gritty of what’s involved, this post was pointless. You essentially spent a entire blog post talking about a non-issue. Surely there must be more “real” issues you are encountering that would be worthy of a post..Yeah I get it that cross-compiler needs to preserve internal consistency, but in this example you give us, it already does..move along nothing to see here…whats next?