Cash Register in Cash Register challenge is stealing money!

Tell us what’s happening:
Dear Campers,
I have started the Cash Register Challenge and have run into a strange behaviour.
When I sum all the cash in the register cid using .reduce, I get a strange rounding error.
Instead of $335.41 I get $335.40999999999997.

While this behaviour is quite amusing, it also tells me that there are processes “under the hood” that I am not aware of…

So does anyone know why this is happening?
What pitfalls can I avoid in the future when implementing .reduce?

  **Your code so far**

function checkCashRegister(price, cash, cid) {
let changeDue = cash - price;
let sumInDrawer = cid.reduce((sum, a) => sum + a[1], 0);
console.log(changeDue, sumInDrawer);
return change;
}

checkCashRegister(19.5, 20, [["PENNY", 1.01], ["NICKEL", 2.05], ["DIME", 3.1], ["QUARTER", 4.25], ["ONE", 90], ["FIVE", 55], ["TEN", 20], ["TWENTY", 60], ["ONE HUNDRED", 100]]);
  **Your browser information:**

User Agent is: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.72 Safari/537.36 Edg/89.0.774.45.

Challenge: Cash Register

Link to the challenge:

Computers can’t actually represent every possible decimal value with floating point numbers. A typical floating point number typically is accurate to at best 15-17 digits. This means that little roundoff errors can accumulate as you do math with floating point numbers, which is what you are seeing.

Personally, I think the easiest way around this is to use an integer number of cents in your cash register. You won’t lose any accuracy unless you try to use a number of cents larger than the largest integer JS can represent with its normal number type (2^53 - 1). If your store is making more than $90,071,992,547,409.91, you’re doing pretty well :slight_smile:

That’s fascinating and very interesting.
Is the rounding-off a built in behaviour or is it a by-product/limitation?

Thank you.

1 Like

Its inherent in how computers store numbers.

A single precision floating point number only has 32 bits (0s and 1s) to represent the digits, exponent, and sign of a number, in a sort of binary scientific notation.

/*
            ↓ sign
             ↓ digits ↓
                        ↓ exponent
*/
let myNum = -5.76823534*10^12

This limits how precisely a number can be represented in the single precision format.

A double precision floating point number does better, with 64 bits, but that still only gives us ~15-17 digits of accuracy in base 10.

The rough analogue is how wide of a sheet of paper do you have to do your arithmetic on in grade school. You can only write so many digits before you run out of space on the paper, or in your computer’s memory.

There are arbitrary precision number formats, but they tend to be pretty special use - most applications have a way to bypass this sort of limitation or can tolerate a little bit of roundoff error.