For reference, this code corresponds this codecademy exercise.
It's a simple cart/checkout program that registers an item and adds its cost to the total, it also takes a item quantity value.
Note: I had previously read about javascript being weird about math, so I was not shoked, but I'm very curious and interested in understanding what's the behavior in this particular case so maybe I'll get some insight to be able to prevent this sort of situation in the future.
So, I have 2 solutions to the exercise, the first one is OK-ish- and the second one has no problems, I guess. Here they are:
1rst one
Independently from the fact that this first approach is inefficient (going through all the posible cases multiple times and adding the item cost over and over). What caught my eye were the extra decimal values that got returned.
var cashRegister = {
total:0,
add: function(itemCost){
this.total += itemCost;
},
scan: function(item,quantity) {
for (var i = 1 ; i <= quantity ; i++ ){
switch (item) {
case "eggs": this.add(0.98); break;
case "milk": this.add(1.23); break;
case "magazine": this.add(4.99); break;
case "chocolate": this.add(0.45); break;
}
}
}
};
// scan each item 4 times
cashRegister.scan("eggs",4);
console.log('Your bill is '+ cashRegister.total);
cashRegister.scan("milk",4);
console.log('Your bill is '+ cashRegister.total);
cashRegister.scan("magazine",4);
console.log('Your bill is '+ cashRegister.total);
cashRegister.scan("chocolate",4);
console.log('Your bill is '+ cashRegister.total);
Console output:
Your bill is 3.92
Your bill is 8.840000000000002
Your bill is 28.800000000000004
Your bill is 30.6
Your bill is 30.6
2nd one
This solution multiplies the item quantity to any that happens to be the case.
var cashRegister = {
total:0,
add: function(itemCost){
this.total += itemCost;
},
scan: function(item,quantity) {
switch (item) {
case "eggs": this.add(0.98*quantity); break;
case "milk": this.add(1.23*quantity); break;
case "magazine": this.add(4.99*quantity); break;
case "chocolate": this.add(0.45*quantity); break;
}
}
};
// scan each item 4 times
cashRegister.scan("eggs",4);
console.log('Your bill is '+cashRegister.total);
cashRegister.scan("milk",4);
console.log('Your bill is '+cashRegister.total);
cashRegister.scan("magazine",4);
console.log('Your bill is '+cashRegister.total);
cashRegister.scan("chocolate",4);
console.log('Your bill is '+cashRegister.total);
Console output is clean:
Your bill is 3.92
Your bill is 8.84
Your bill is 28.8
Your bill is 30.6
Your bill is 30.6
So, what is going on with the first solution so that the decimal extravaganza gets returned?
Thank you very much in advance.
EDIT: Thank you for your attempts to help me with my doubts. Though I realized I need to make it clear that I'm aware "JavaScript uses floating point values for its number type and the loss of precision is the cause for this".
The real question is:
Why does the same calculation loses precision on the 1st solution but not the 2nd solution?