Floating point numbers in JS

Javascript

1 + 1

2

Javascript

0.1 + 0.1

0.2

Javascript

0.1 + 0.2

0.30000000000000004

Java

0.1 + 0.2

0.30000000000000004

Java

0.1f + 0.2f

0.3

IEEE 754

  • Sign: 0 => positive, 1 => negative
  • Exponent: number of digits left or right the floating point that should be shifted
  • Mantissa: binary digits of the number. Whole numbers => 2x, decimals => 2-x (or 1/2x)

Additional information

  • +Infinity: Sign 0; Exponent 2047; Mantissa 0
  • -Infinity: Sign 1; Exponent 2047; Mantissa 0
  • NaN: Sign 0/1; Exponent 2047; Mantissa !== 0

What happens ?

  • 100 (binary) = 4. (1 x 22 + 0 x 21 + 0 x 20 = 4)
  • In JS numbers, any digit that exceeds the 52 bits of the mantissa are assumed to be 0
  • JS numbers are converted from decimal to binary
  • 0.125 in decimal = 125/1000 = 1/8 = 1/23 = 0.001 in binary
  • 0.1 in decimal = 1/10 = 1/2 * 5
  • 0.2 in decimal = 1/20 = 1/2 * 2 * 5
  • πŸ€” The decimal values in our binary representation are defined using 2-x (or 1/2x)
  • 😱 No way to cleanly find a exponent that our number goes into
  • πŸƒ We’ll continue to get back decimal/fraction results until we run out of bits
  • πŸ’Ύ When the conversion exhausts its bits, it’ll store the result
  • πŸ€·β€ In this case it ends in 100 in binary or 4

How to avoid that?

  • Stop using JavaScript 😜
  • Scale up our result to an integer and scale back after
  • Example: 0.1 * 10, 0.2 * 10 = 1.0 + 2.0 = 3.0/10 = 0.3

toPrecision() and toFixed() for display purposes only

```js function foo(x, y) { return x.toPrecision() + y.toPrecision() } > foo(0.1, 0.2) "0.10.2" ```

Math libraries

  • sinful.js
  • math.js
  • BigDecimal

Links