Search code examples
javascriptfloating-accuracyfloating-point-precision

Is there a way to distinguish integers from very near decimals in Javascript?


Look at those evaluations (actual dump from node 0.10.33)

> parseFloat(2.1e-17) === parseInt(2.1e-17)
false
> parseFloat(2.1e-17 + 2) === parseInt(2.1e-17 + 2)
true
> parseFloat(2.000000000000000000000000000000000009) === parseInt(2.00000000000000000000000000000000000009)
true

How can I tell integers from decimals very near to integers?

It seems that JS (or at least V8) doesn't care about digits smaller than 10^-16 when doing calculations, even if the 64bit representation used by the language (reference) should handle it.


Solution

  • Your examples are pretty much straight forward to explain. First thing to note is, that parseInt() and parseFloat() take a string as an input. So you inputs first get converted to string, before actually getting parsed.

    The first is easy to see:

    > parseFloat(2.1e-17) === parseInt(2.1e-17)
    false
    
    // look at the result of each side
    parseFloat(2.1e-17) == 2.1e-17
    parseInt(2.1e-17)  == 2
    

    When parsing the string "2.1e-17" as integer, the parse will stop at the dot as that is no valid digit and return everything it found until then, which is just 2.

    > parseFloat(2.1e-17 + 2) === parseInt(2.1e-17 + 2)
    true
    
    // look at the result of each side
    parseFloat(2.1e-17 + 2) == 2
    parseInt(2.1e-17 + 2)  == 2
    

    Here the formula in the parameter will be evaluated first. Due to the limitations of floating point math (we just have 52bit for the mantissa and can't represent something like 2.000000000000000021), this will result in just 2. So both parseX() function get the same integer parameter, which will result in the same parsed number.

    > parseFloat(2.000000000000000000000000000000000009) === parseInt(2.00000000000000000000000000000000000009)
    true
    

    Same argument as for the second case. The only difference is, that instead of a formula, that gets evaluated, this time it is the JavaScript parser, which converts your numbers just to 2.


    So to sum up: From JavaScript's point of view, your numbers are just the same. If you need more precision, you will have to use some library for arbitrary precision.