Why JavaScript Doesn't Handle Money Very Well and How To Fix It

When building JavaScript applications that perform calculations involving money, you may be surprised with the results it produces. For example, 1.01 + 2.02 = 3.0300000000000002. This probably isn't the result you expected; I would have expected 3.03.

The Problem

So, let's take a closer look into this issue. JavaScript has only one data type for representing numeric values, the Number data type which is implemented as a floating-point number. Floating-point numbers are not able to handle all non-integer values with 100% accuracy which introduces approximate numbers into our calculations.

Here's some code that demonstrates the results of adding numbers in JavaScript:

Adding Numbers in JavaScript

Lines 20-23 build an array consisting of all the numbers between 0 and 0.99 inclusive. The call to function displayNumbers outputs this array to the console separating each value with a comma. Here's the resulting console output from this function:

numbers: 0, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.1, 0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.2, 0.21, 0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.3, 0.31, 0.32, 0.33, 0.34, 0.35, 0.36, 0.37, 0.38, 0.39, 0.4, 0.41, 0.42, 0.43, 0.44, 0.45, 0.46, 0.47, 0.48, 0.49, 0.5, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.57, 0.58, 0.59, 0.6, 0.61, 0.62, 0.63, 0.64, 0.65, 0.66, 0.67, 0.68, 0.69, 0.7, 0.71, 0.72, 0.73, 0.74, 0.75, 0.76, 0.77, 0.78, 0.79, 0.8, 0.81, 0.82, 0.83, 0.84, 0.85, 0.86, 0.87, 0.88, 0.89, 0.9, 0.91, 0.92, 0.93, 0.94, 0.95, 0.96, 0.97, 0.98, 0.99

Line 26 interates thorough all of these numbers executing function processFirstNumber for each one. Line 13 does the same thing iterating through all of these number as well. So, the functions processFirstNumber and processSecondNumber produce all of the possible combinations for adding two numbers ranging from 0 to 0.99. The function processSecondNumber executes function displayResult for every combination (a and b). The function displayResult adds the two numbers together and logs the equation to the console if the result is contains more than 4 characters. These are the results affected by floating-point approximations. Here's the resulting console output from function displayResult:

0.01 + 0.05 = 0.060000000000000005
0.01 + 0.06 = 0.06999999999999999
0.01 + 0.09 = 0.09999999999999999
0.01 + 0.14 = 0.15000000000000002
0.01 + 0.17 = 0.18000000000000002
0.01 + 0.2 = 0.21000000000000002
0.01 + 0.23 = 0.24000000000000002
0.01 + 0.28 = 0.29000000000000004
0.01 + 0.34 = 0.35000000000000003
0.01 + 0.4 = 0.41000000000000003
0.01 + 0.46 = 0.47000000000000003
0.01 + 0.56 = 0.5700000000000001
0.01 + 0.68 = 0.6900000000000001
0.01 + 0.81 = 0.8200000000000001
0.01 + 0.93 = 0.9400000000000001
0.02 + 0.07 = 0.09000000000000001
0.02 + 0.1 = 0.12000000000000001
0.02 + 0.12 = 0.13999999999999999
0.02 + 0.15 = 0.16999999999999998
0.02 + 0.18 = 0.19999999999999998
0.02 + 0.21 = 0.22999999999999998
0.02 + 0.27 = 0.29000000000000004
0.02 + 0.28 = 0.30000000000000004
0.02 + 0.33 = 0.35000000000000003
0.02 + 0.34 = 0.36000000000000004
0.02 + 0.39 = 0.41000000000000003
0.02 + 0.4 = 0.42000000000000004
0.02 + 0.45 = 0.47000000000000003
0.02 + 0.46 = 0.48000000000000004
0.02 + 0.55 = 0.5700000000000001
0.02 + 0.56 = 0.5800000000000001
0.02 + 0.67 = 0.6900000000000001
0.02 + 0.68 = 0.7000000000000001
0.02 + 0.8 = 0.8200000000000001
0.02 + 0.81 = 0.8300000000000001
0.02 + 0.92 = 0.9400000000000001
0.02 + 0.93 = 0.9500000000000001
0.03 + 0.26 = 0.29000000000000004
0.03 + 0.27 = 0.30000000000000004
0.03 + 0.28 = 0.31000000000000005
0.03 + 0.29 = 0.31999999999999995
0.03 + 0.3 = 0.32999999999999996
0.03 + 0.31 = 0.33999999999999997
0.03 + 0.38 = 0.41000000000000003
0.03 + 0.39 = 0.42000000000000004
0.03 + 0.4 = 0.43000000000000005
0.03 + 0.41 = 0.43999999999999995
0.03 + 0.42 = 0.44999999999999996
0.03 + 0.43 = 0.45999999999999996
0.03 + 0.54 = 0.5700000000000001
0.03 + 0.55 = 0.5800000000000001
0.03 + 0.56 = 0.5900000000000001
0.03 + 0.66 = 0.6900000000000001
0.03 + 0.67 = 0.7000000000000001
0.03 + 0.68 = 0.7100000000000001
0.03 + 0.79 = 0.8200000000000001
0.03 + 0.8 = 0.8300000000000001
0.03 + 0.81 = 0.8400000000000001
0.03 + 0.91 = 0.9400000000000001
0.03 + 0.92 = 0.9500000000000001
0.03 + 0.93 = 0.9600000000000001
(The rest of the output is not shown.)

As we can see in the above calculations, the result of adding non-integer numbers is very close to the expected result but not exact.

The Solution

Rounding each result to two decimal places gives us the result we're expecting. JavaScript has a utility function named Math.round(). However, this function returns the value of a number rounded to the nearest integer. So, we could utilize this function to round the result of our calculations, however, we'd have to first multiple the result by 100, round it and then divide the result by 100. Here's how this code would look:

Adding Numbers in JavaScript with Rounding

In function displayResult, lines 8-12 round the result and log it to the console. Here's the resulting output with the rounding logic in place:

0.01 + 0.05 = 0.060000000000000005
0.01 + 0.05 = 0.06

0.01 + 0.06 = 0.06999999999999999
0.01 + 0.06 = 0.07

0.01 + 0.09 = 0.09999999999999999
0.01 + 0.09 = 0.1

0.01 + 0.14 = 0.15000000000000002
0.01 + 0.14 = 0.15

0.01 + 0.17 = 0.18000000000000002
0.01 + 0.17 = 0.18

0.01 + 0.2 = 0.21000000000000002
0.01 + 0.2 = 0.21

0.01 + 0.23 = 0.24000000000000002
0.01 + 0.23 = 0.24

0.01 + 0.28 = 0.29000000000000004
0.01 + 0.28 = 0.29

0.01 + 0.34 = 0.35000000000000003
0.01 + 0.34 = 0.35

0.01 + 0.4 = 0.41000000000000003
0.01 + 0.4 = 0.41

0.01 + 0.46 = 0.47000000000000003
0.01 + 0.46 = 0.47

0.01 + 0.56 = 0.5700000000000001
0.01 + 0.56 = 0.57

0.01 + 0.68 = 0.6900000000000001
0.01 + 0.68 = 0.69

0.01 + 0.81 = 0.8200000000000001
0.01 + 0.81 = 0.82

0.01 + 0.93 = 0.9400000000000001
0.01 + 0.93 = 0.94

0.02 + 0.07 = 0.09000000000000001
0.02 + 0.07 = 0.09

0.02 + 0.1 = 0.12000000000000001
0.02 + 0.1 = 0.12

0.02 + 0.12 = 0.13999999999999999
0.02 + 0.12 = 0.14

0.02 + 0.15 = 0.16999999999999998
0.02 + 0.15 = 0.17

0.02 + 0.18 = 0.19999999999999998
0.02 + 0.18 = 0.2

0.02 + 0.21 = 0.22999999999999998
0.02 + 0.21 = 0.23

0.02 + 0.27 = 0.29000000000000004
0.02 + 0.27 = 0.29

0.02 + 0.28 = 0.30000000000000004
0.02 + 0.28 = 0.3

0.02 + 0.33 = 0.35000000000000003
0.02 + 0.33 = 0.35

0.02 + 0.34 = 0.36000000000000004
0.02 + 0.34 = 0.36

0.02 + 0.39 = 0.41000000000000003
0.02 + 0.39 = 0.41

0.02 + 0.4 = 0.42000000000000004
0.02 + 0.4 = 0.42

0.02 + 0.45 = 0.47000000000000003
0.02 + 0.45 = 0.47

0.02 + 0.46 = 0.48000000000000004
0.02 + 0.46 = 0.48

0.02 + 0.55 = 0.5700000000000001
0.02 + 0.55 = 0.57

0.02 + 0.56 = 0.5800000000000001
0.02 + 0.56 = 0.58

0.02 + 0.67 = 0.6900000000000001
0.02 + 0.67 = 0.69

0.02 + 0.68 = 0.7000000000000001
0.02 + 0.68 = 0.7

0.02 + 0.8 = 0.8200000000000001
0.02 + 0.8 = 0.82

0.02 + 0.81 = 0.8300000000000001
0.02 + 0.81 = 0.83

0.02 + 0.92 = 0.9400000000000001
0.02 + 0.92 = 0.94

0.02 + 0.93 = 0.9500000000000001
0.02 + 0.93 = 0.95

0.03 + 0.26 = 0.29000000000000004
0.03 + 0.26 = 0.29

0.03 + 0.27 = 0.30000000000000004
0.03 + 0.27 = 0.3

0.03 + 0.28 = 0.31000000000000005
0.03 + 0.28 = 0.31

0.03 + 0.29 = 0.31999999999999995
0.03 + 0.29 = 0.32

0.03 + 0.3 = 0.32999999999999996
0.03 + 0.3 = 0.33

0.03 + 0.31 = 0.33999999999999997
0.03 + 0.31 = 0.34

0.03 + 0.38 = 0.41000000000000003
0.03 + 0.38 = 0.41

0.03 + 0.39 = 0.42000000000000004
0.03 + 0.39 = 0.42

0.03 + 0.4 = 0.43000000000000005
0.03 + 0.4 = 0.43

0.03 + 0.41 = 0.43999999999999995
0.03 + 0.41 = 0.44

0.03 + 0.42 = 0.44999999999999996
0.03 + 0.42 = 0.45

0.03 + 0.43 = 0.45999999999999996
0.03 + 0.43 = 0.46

0.03 + 0.54 = 0.5700000000000001
0.03 + 0.54 = 0.57

0.03 + 0.55 = 0.5800000000000001
0.03 + 0.55 = 0.58

0.03 + 0.56 = 0.5900000000000001
0.03 + 0.56 = 0.59

0.03 + 0.66 = 0.6900000000000001
0.03 + 0.66 = 0.69

0.03 + 0.67 = 0.7000000000000001
0.03 + 0.67 = 0.7

0.03 + 0.68 = 0.7100000000000001
0.03 + 0.68 = 0.71

0.03 + 0.79 = 0.8200000000000001
0.03 + 0.79 = 0.82

0.03 + 0.8 = 0.8300000000000001
0.03 + 0.8 = 0.83

0.03 + 0.81 = 0.8400000000000001
0.03 + 0.81 = 0.84

0.03 + 0.91 = 0.9400000000000001
0.03 + 0.91 = 0.94

0.03 + 0.92 = 0.9500000000000001
0.03 + 0.92 = 0.95

0.03 + 0.93 = 0.9600000000000001
0.03 + 0.93 = 0.96

So, our results now contains the values we expect. However, this requires us to multiply by 100, round and divide by 100 every time we compute a value. We can make this easier by adding a toCurrency function to the Math object. This would enable us to fix the results of our calculations like this:

var sum = Math.toCurrency(a + b);

Here's the implementation for the toCurrency function:

Add toCurrency function to Math Object

Here's the refactored version of function displayResult utilizing our new toCurrency function:

Refactored Version of Function displayResult Using Function toCurrency

This version of the code produces the same result as follows:

0.01 + 0.05 = 0.060000000000000005
0.01 + 0.05 = 0.06

0.01 + 0.06 = 0.06999999999999999
0.01 + 0.06 = 0.07

0.01 + 0.09 = 0.09999999999999999
0.01 + 0.09 = 0.1

0.01 + 0.14 = 0.15000000000000002
0.01 + 0.14 = 0.15

0.01 + 0.17 = 0.18000000000000002
0.01 + 0.17 = 0.18

0.01 + 0.2 = 0.21000000000000002
0.01 + 0.2 = 0.21

0.01 + 0.23 = 0.24000000000000002
0.01 + 0.23 = 0.24

0.01 + 0.28 = 0.29000000000000004
0.01 + 0.28 = 0.29

0.01 + 0.34 = 0.35000000000000003
0.01 + 0.34 = 0.35

0.01 + 0.4 = 0.41000000000000003
0.01 + 0.4 = 0.41

0.01 + 0.46 = 0.47000000000000003
0.01 + 0.46 = 0.47

0.01 + 0.56 = 0.5700000000000001
0.01 + 0.56 = 0.57

0.01 + 0.68 = 0.6900000000000001
0.01 + 0.68 = 0.69

0.01 + 0.81 = 0.8200000000000001
0.01 + 0.81 = 0.82

0.01 + 0.93 = 0.9400000000000001
0.01 + 0.93 = 0.94

0.02 + 0.07 = 0.09000000000000001
0.02 + 0.07 = 0.09

0.02 + 0.1 = 0.12000000000000001
0.02 + 0.1 = 0.12

0.02 + 0.12 = 0.13999999999999999
0.02 + 0.12 = 0.14

0.02 + 0.15 = 0.16999999999999998
0.02 + 0.15 = 0.17

0.02 + 0.18 = 0.19999999999999998
0.02 + 0.18 = 0.2

0.02 + 0.21 = 0.22999999999999998
0.02 + 0.21 = 0.23

0.02 + 0.27 = 0.29000000000000004
0.02 + 0.27 = 0.29

0.02 + 0.28 = 0.30000000000000004
0.02 + 0.28 = 0.3

0.02 + 0.33 = 0.35000000000000003
0.02 + 0.33 = 0.35

0.02 + 0.34 = 0.36000000000000004
0.02 + 0.34 = 0.36

0.02 + 0.39 = 0.41000000000000003
0.02 + 0.39 = 0.41

0.02 + 0.4 = 0.42000000000000004
0.02 + 0.4 = 0.42

0.02 + 0.45 = 0.47000000000000003
0.02 + 0.45 = 0.47

0.02 + 0.46 = 0.48000000000000004
0.02 + 0.46 = 0.48

0.02 + 0.55 = 0.5700000000000001
0.02 + 0.55 = 0.57

0.02 + 0.56 = 0.5800000000000001
0.02 + 0.56 = 0.58

0.02 + 0.67 = 0.6900000000000001
0.02 + 0.67 = 0.69

0.02 + 0.68 = 0.7000000000000001
0.02 + 0.68 = 0.7

0.02 + 0.8 = 0.8200000000000001
0.02 + 0.8 = 0.82

0.02 + 0.81 = 0.8300000000000001
0.02 + 0.81 = 0.83

0.02 + 0.92 = 0.9400000000000001
0.02 + 0.92 = 0.94

0.02 + 0.93 = 0.9500000000000001
0.02 + 0.93 = 0.95

0.03 + 0.26 = 0.29000000000000004
0.03 + 0.26 = 0.29

0.03 + 0.27 = 0.30000000000000004
0.03 + 0.27 = 0.3

0.03 + 0.28 = 0.31000000000000005
0.03 + 0.28 = 0.31

0.03 + 0.29 = 0.31999999999999995
0.03 + 0.29 = 0.32

0.03 + 0.3 = 0.32999999999999996
0.03 + 0.3 = 0.33

0.03 + 0.31 = 0.33999999999999997
0.03 + 0.31 = 0.34

0.03 + 0.38 = 0.41000000000000003
0.03 + 0.38 = 0.41

0.03 + 0.39 = 0.42000000000000004
0.03 + 0.39 = 0.42

0.03 + 0.4 = 0.43000000000000005
0.03 + 0.4 = 0.43

0.03 + 0.41 = 0.43999999999999995
0.03 + 0.41 = 0.44

0.03 + 0.42 = 0.44999999999999996
0.03 + 0.42 = 0.45

0.03 + 0.43 = 0.45999999999999996
0.03 + 0.43 = 0.46

0.03 + 0.54 = 0.5700000000000001
0.03 + 0.54 = 0.57

0.03 + 0.55 = 0.5800000000000001
0.03 + 0.55 = 0.58

0.03 + 0.56 = 0.5900000000000001
0.03 + 0.56 = 0.59

0.03 + 0.66 = 0.6900000000000001
0.03 + 0.66 = 0.69

0.03 + 0.67 = 0.7000000000000001
0.03 + 0.67 = 0.7

0.03 + 0.68 = 0.7100000000000001
0.03 + 0.68 = 0.71

0.03 + 0.79 = 0.8200000000000001
0.03 + 0.79 = 0.82

0.03 + 0.8 = 0.8300000000000001
0.03 + 0.8 = 0.83

0.03 + 0.81 = 0.8400000000000001
0.03 + 0.81 = 0.84

0.03 + 0.91 = 0.9400000000000001
0.03 + 0.91 = 0.94

0.03 + 0.92 = 0.9500000000000001
0.03 + 0.92 = 0.95

0.03 + 0.93 = 0.9600000000000001
0.03 + 0.93 = 0.96

The benefit of adding the toCurrency function to the Math object (patching) is that toCurrency is made available to all parts of our application and we're keeping our code DRY (Don't Repeat Yourself).

JavaScript has only one data type to represent all numbers which is in the floating-point format. As a result, some non-integer numbers cannot be represented exactly. The approach I've presented is to round these numbers to two decimal places using a function named toCurrency I've added to the Math object.