4 ms·
Yes, this is the best way to explain it. Your number literals are “snapping to a grid” that is not base-10 and then we choose the shortest base-10 decimal that
by crdrost 4y ago
Yes, this is the best way to explain it. Your number literals are “snapping to a grid” that is not base-10 and then we choose the shortest base-10 decimal that snaps to the appropriate grid point when we stringify the number.
The other thing that I would mention is that I see some really gnarly workarounds to try to get around this... Just bump up to integers for a second! People have this mistaken idea that the best way to understand these rounding “errors” is that floating point is just unpredictably noisy for everything, and that's not true.
Floating point has an exact representation of all integers up to 2^53 – 1. If you are dealing with dollars and cents that clients are getting billed or whatever, okay, the best thing to do is to have a decimal library. But if you don't have a decimal library and it's just some in-game currency that you don't want to get these gnarly decimals on, 3/10 will always give 0.3. 4/100 will always give 0.04. Just use the fact that the integer arithmetic is exact: multiply by the base, round to nearest integer, do your math, and then divide out the base in the end: and you'll be good.
- ClumsyPilot 4y ago> If you are dealing with dollars and cents that clients are getting billed or whatever, okay, the best thing to do is to have a decimal library. C# has decimal in the base library. We are doing a new project with financial data, and decided we willvhave everything in decimal - no floats at all. There is no point of dealing with these issues to save irrelevant amount of CPU
- toast0 4y agoA reasonable, but not always available, choice is to use integer quantities of the divided quantity. If you're dollars and cents, express things in cents. If you need tenths of a cent, express things in milliDollars. If you need 1/8th dollars, use those. Have a conversion to pretty values when displayed. Sometimes you really do need to have a pretty good estimate of pi dollars, but often not.
- 8n4vidtmkvmk 4y agowhat i haven't figured out is multicurrency. "cents" is fine for dollars but 1/100 doesn't work for all currencies. do you use a different denominator for each currency or standardize on 1/1e8 or something?
- toast0 4y agoI'd use a different denominator per currency? You've got to keep track of the currency anyway, so have 1 USDCent, or 1 EURCent or 1 BHDFil (1/1000) or 1 GBPPence (1/100) or the historic 1 GBPFarthing (1/960 ??) If the wikipedia article on Decimalisation[1] is complete and accurate, only Mauritania and Madagascar still have non-decimal currencies. If you really needed it to be uniform, you could work in 1/1000th worldwide, as long as you didn't need to keep more decimals for other reasons. [1] https://en.wikipedia.org/wiki/Decimalisation https://en.wikipedia.org/wiki/Decimalisation
- int_19h 4y agoAnd it's very bad UX that when you write "0.1" in the code or feed it to the standard string parser at runtime, what you get back is not actually 0.1. It's effectively silent data corruption. If you want "snapping to a grid" for perf reasons, it should be opt-in, not opt-out.