$ node
> 0.1 + 0.2 - 0.3
5.551115123125783e-17
Close enough for trivial cases but errors can accumulate.Ruby, Perl5, Python also fail this. Perl6 uses Rat numbers for things like this and doesn't have this problem.
My experience has been, though, that many developers have a bit of a laissez-faire attitude towards these kinds of details (time is, of course, another area where precision is incredibly important in corner cases). Rather than expecting all future programmers to be as diligent as they need to be, it's probably easier to simply use tools that make it difficult to make mistakes. Every time I'm working on financial systems I build currency classes (usually I'm doing OOP). Usually people grumble and there will be people who ignore the currency classes. I've never had to wait long before someone trips over an edge cases and everybody understands the benefits.
Ruby and Python have arbitrary precision decimal and rational support in the standard library. While there are arguments tobe had over whether using binary floats by default for simple decimal literals is a good choice, that's a different issue than not having any other kind of numbers available by default.
Do the same with a proper decimal datatype, and the same operations give the correct result - pay out 1/3=0.33; pay out 1/3=0.33; the last payment is 1-0.33-0.33 = 0.34 exactly.
The same goes with all kinds of other issues e.g. totalling up tax or discount amounts (calculated as a percentage) where you'll get mismatches if rounding happens at the wrong time, etc.
E.g. ten separate receipts each selling a 0.10 item with a 9% tax or discount will result in each receipt having 0.01 tax or discount; so the proper total in this case is 1.00 sales with 0.10 tax or discount; different than the case if you sell ten such items in a single transaction. If you do all the calculations in floats, you get this wrong.
(1.005).toFixed(2) // Expected rounding to "1.01"
"1.00"2.875.toFixed(2) = "2.88" while 2.675.toFixed(2) = "2.67"
7205759403792794 + 1.1 = 7205759403792795
7205759403792794 + 1.9 = 7205759403792796
for (let n = 0; n < 1; n += .01) { console.log(`n: ${n}, half: ${(n / 2).toFixed(2)}`); }
According to this https://www.h-schmidt.net/FloatConverter/IEEE754.html
2.1 will be represented as 2.099999904632568359375
For single precision floats you start having issues representing integers as low as 16777217
I know you knew what I meant.
People believing that a float type can represent all integers that the int type in their language can represent is not exactly uncommon.