I'm writing a change-making script and JavaScript is processing 76.74 - 20
as 56.739999999999995
. The line in question is marked clearly in a comment below.
function checkCashRegister(price, cash, cid) {
let drawer = cid; // Changeable copy of cash in drawer
let change = [];
let changeLeft = cash - price;
console.log(`initial changeLeft = ${changeLeft}`);
let registerTemplate = [
["PENNY", 0.01], // 0
["NICKEL", 0.05], // 1
["DIME", 0.10], // 2
["QUARTER", 0.25], // 3
["ONE", 1.00], // 4
["FIVE", 5.00], // 5
["TEN", 10.00], // 6
["TWENTY", 20.00], // 7
["ONE HUNDRED", 100.00] // 8
];
for (let i = 8; i >= 0; i--) {
if (changeLeft >= registerTemplate[i][1]) {
let counter = 0;
while (drawer[i][1] >= registerTemplate[i][1] && changeLeft >= registerTemplate[i][1]) {
drawer[i][1] -= registerTemplate[i][1];
changeLeft -= registerTemplate[i][1]; // THIS IS THE LINE IN QUESTION
console.log(`just removed ${registerTemplate[i][1]} and changeLeft = ${changeLeft}`);
counter++;
}
if (counter > 0) {
change.push([registerTemplate[i][0], counter * registerTemplate[i][1]]);
}
}
}
console.log(`changeLeft is ${changeLeft}`);
if (changeLeft > 0) {
return {status: "INSUFFICIENT_FUNDS", change: []};
} else if (changeLeft == 0) {
return {status: "OPEN", change: change};
} else {
return {status: "OPEN", change: [...change]};
}
}
console.log(checkCashRegister(3.26, 100, [["PENNY", 1.01], ["NICKEL", 2.05], ["DIME", 3.1], ["QUARTER", 4.25], ["ONE", 90], ["FIVE", 55], ["TEN", 20], ["TWENTY", 60], ["ONE HUNDRED", 100]]));
This is the console readout after running the script (I'm in VS Code if that's relevant):
initial changeLeft = 96.74
just removed 20 and changeLeft = 76.74
just removed 20 and changeLeft = 56.739999999999995
just removed 20 and changeLeft = 36.739999999999995
just removed 10 and changeLeft = 26.739999999999995
just removed 10 and changeLeft = 16.739999999999995
just removed 5 and changeLeft = 11.739999999999995
just removed 5 and changeLeft = 6.739999999999995
just removed 5 and changeLeft = 1.7399999999999949
just removed 1 and changeLeft = 0.7399999999999949
just removed 0.25 and changeLeft = 0.4899999999999949
just removed 0.25 and changeLeft = 0.23999999999999488
just removed 0.1 and changeLeft = 0.13999999999999488
just removed 0.1 and changeLeft = 0.03999999999999487
just removed 0.01 and changeLeft = 0.02999999999999487
just removed 0.01 and changeLeft = 0.01999999999999487
just removed 0.01 and changeLeft = 0.009999999999994869
changeLeft is 0.009999999999994869
As you can see, the second time the value 20 is subtracted is when the calculation starts to be off, and then there are a few more times when the values after the decimal point change slightly again in unexpected ways. The only solution I can think of is to force it to round to two decimal places, which would work as a band-aid fix but not address whatever the underlying problem is here. I found another question that had a similar problem when dealing with high-precision floating points, but that doesn't seem to be the case here since the highest precision is two decimal places. Another possible band-aid fix could be to do all calculations on integers by multiplying everything by 100, then dividing by 100 only at the end, but this again doesn't address the issue.
Thank you in advance.