0

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.

seldon
  • 977
  • 2
  • 8
  • 20

2 Answers2

2

This is something I learned from ReSharper

instead of using expressions like

 if (2.00001 == 2) {}

try

if (Math.abs(2.00001 - 2) < tolerance) {}

where tolerance should be an aceptable value for you for example .001

so all values wich difference is less than .001 will be equals

Do you really need 10^-16 precision I mean that is why 1000 meter = 1 kilometer, just change the unit of the output so you dont have to work with all those decimals

bto.rdz
  • 6,636
  • 4
  • 35
  • 52
  • The problem is the difference will always be zero if they differ from less than 10^-16, and I'm looking for a way to compare two numbers deeper – seldon Nov 11 '14 at 16:44
  • so multiply it by a big number – bto.rdz Nov 11 '14 at 16:46
  • It doesn't work, as I state in the question, operations literally cancel out digits smaller than 10^-16 – seldon Nov 11 '14 at 16:50
  • do you really need 10^-16 precision I mean that is why we have 1000 meter and 1 km, just change the unit of the output so you dont have to work with all those decimals – bto.rdz Nov 11 '14 at 16:53
  • Yes, I need it, and anyway multiplying it doesn't change anything since the number is represented in the same way, as explained in [the reference I linked in the question](http://www.w3schools.com/js/js_numbers.asp) – seldon Nov 11 '14 at 16:58
  • I dont know how your code works, but i guess you ask a user for some parameters, insted of asking for inches ask for microinches, that is how you wont get those small numbers(or convert inches to microinches in your code). its all about the units – bto.rdz Nov 11 '14 at 17:01
  • Changing units won't solve the problem. The problem is about *precision*, how many digits I need to store? If it's more than 16 digits, [64bit numbers don't suffice](http://stackoverflow.com/questions/26869799/is-there-a-way-to-distinguish-integers-from-very-near-decimals-in-javascript/26870025#comment42299284_26870025). However if I need to use `2e-300`, 64bit-numbers are totally fine because they store only 2 and 300, and they don't care about all the zeros. That's [floating point arithmetic](http://en.wikipedia.org/wiki/Floating_point). – seldon Nov 11 '14 at 17:12
  • doubles are not infinite, they have a limit too, units is the problem, but you will find it later, I mean instead of using .0000000001 meters use 1 nanometer http://www.w3schools.com/jsref/jsref_max_value.asp – bto.rdz Nov 11 '14 at 17:16
  • Yes, theoretically you have a limit of `+- 2^11 - 1` for the exponent, but that's not the concern here. Precision is independent from the number "size", and the reason we use floating point arithmetic is just that. Please check the Wikipedia page I linked before. – seldon Nov 11 '14 at 17:25
2

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.

Sirko
  • 72,589
  • 19
  • 149
  • 183
  • Thank you for the answer! I'll actually come to the conclusion that `2e-17 + 2` is rounded because its binary representation [needs more](http://www.wolframalpha.com/input/?i=log2%2810%5E16%29) than the 52bit mantissa provided by a 64bit double. If you add this detail in your answer I'll accept it. – seldon Nov 11 '14 at 17:02
  • 1
    @mattecapu `2e-16` can actually be represented without a problem. The problems start, when you try to evaluate `(1 + 2e-16) `. – Sirko Nov 11 '14 at 17:07
  • 1
    @mattecapu Ah ok. Added a sentence for the bit representation. – Sirko Nov 11 '14 at 17:11