Floating Point errors in JavaScript/Node.js

Elena Sharovar
3 min readOct 10, 2019

When you study JavaScript you’re warned that 0.1 + 0.2 !== 0.3 and everybody knows it, right? It’s equal to 0.30000000000004 and it’s not a JavaScript fault, it’s your processor doing this. So coding in Java or any other language won’t help.

But do you know how often it happens? I decided to check, haha. How this experiment was done: I created a script which iterated through all numbers from 0.01 to 100.00 and did -, +, * and / operations.

Sum

In 22% of SUM operations, there happens this bug.

5.33 + 5.2 === 10.530000000000001
7.84 + 4.28 === 12.120000000000001
11.92 + 207.85 === 219.76999999999998
99.52 + 6.27 === 105.78999999999999
939.92 + 153.49 === 1093.4099999999999
843.32 + 131.47 === 974.7900000000001
36067.29 + 3920.23 === 39987.520000000004
....

Diff

In 56.6% of DIFF operations we get a “bonus”:

8.13 - 5.75 === 2.380000000000001
8.93 - 4.4 === 4.529999999999999
6.09 - 3.43 === 2.6599999999999997
4.95 - 2.82 === 2.1300000000000003
986.83 - 93.44 === 893.3900000000001
119.93 - 43.35 === 76.58000000000001
490.01 - 10.91 === 479.09999999999997
122.72 - 6.43 === 116.28999999999999
....

Multiplication

It happens:

  • in 17% of operations when you do [integer] * [floating-point]
  • in 36% of cases when you do [floating-point] * [floating-point]
  • in 0% when you do [integer] * [integer] (it’s expected)
8.38 * 0.3 === 2.5140000000000002
9.16 * 8.22 === 75.29520000000001
3.37 * 3.33 === 11.222100000000001
9.68 * 8.22 === 79.56960000000001
89.86 * 9.46 === 850.0756000000001
73.85 * 7.81 === 576.7684999999999
21.39 * 1.27 === 27.165300000000002
80.04 * 8.66 === 693.1464000000001
71.64 * 4.64 === 332.40959999999995

Division

How often does it happen?

  • in 16.4% of operations when you do [floating-point] / [integer]
  • in 26% of operations when you do [integer] / [floating-point]
  • in 36% of cases when you do [floating-point] / [floating-point]
  • in 0% when you do integer / integer
99.27 / 3 == 33.089999999999996 (should be 33.09)
57.3 / 3 == 19.099999999999998 (should be 19.1)
73.15 / 7 == 10.450000000000001 (should be 10.45)
58.2 / 3 == 19.400000000000002 (should be 19.4)
69.96 / 3 == 23.319999999999997 (should be 23.32)
32.76 / 9 == 3.6399999999999997 (should be 3.64)
28.62 / 3 == 9.540000000000001 (should be 9.54)

parseFloat

parseFloat never makes mistakes. It never returns 54.5999999999994 if you pass 54.6 string to it. It returns exactly54.6

parseFloat('54.6') // 54.6
parseFloat('123.45678901') // 123.45678901
parseFloat('54.599999999999994') // 54.599999999999994

Is “a + b + c” always equal to “c + b + a”?

Nope! Did your teacher of math tell that to you? See:

85.13 + 5.96 + 8.44 === 99.52999999999999
8.44 + 5.96 + 85.13 === 99.53

94.4 + 7.12 + 4.67 === 106.19000000000001
4.67 + 7.12 + 94.4 === 106.19

43.57 + 5.33 + 3.05 === 51.949999999999996
3.05 + 5.33 + 43.57 === 51.95

Summary

Don’t hope that floating-point errors are rare. They happen in 17–56% of all mathematical operations, so there’s a very high chance that you’ll get this bug.

When you write unit tests or do manual testing, use the numbers I shared here. And tell me in comments how many bugs did you find :)

I shared more examples here so that you could use them in your unit tests: https://github.com/ellenaua/floating-point-error-examples/tree/master/examples

How to avoid this?

Use numeral.js or decimal.js for exact math.

--

--