5 ms·
I really like this quote from the article as way of explaining this whole perceived anomaly: > To me, 0.1000000000000000055511151231257827021181583404541015625
by adunk 4y ago
I really like this quote from the article as way of explaining this whole perceived anomaly:
> To me, 0.1000000000000000055511151231257827021181583404541015625 + 0.200000000000000011102230246251565404236316680908203125 = 0.3000000000000000444089209850062616169452667236328125 feels less surprising than 0.1 + 0.2 = 0.30000000000000004.
- lifthrasiir 4y agoAnd in my opinion, this is why `0.1 + 0.2 = 0.30000000000000004` is a bad meme. It cements a very wrong perception about floating point numbers. If we denote a rounding operation as `f64(...)`, this is `f64(f64(0.1) + f64(0.2)) = f64(0.30000000000000004) != f64(0.1 + 0.2)` which can obviously happen. In particular, `f64(0.1) != 0.1` etc. but we happened to choose 0.1 as a representative for `f64(0.1)` for various reasons. Nothing inaccurate, nothing meme-worthy, just implied operations.
- crdrost 4y agoYes, 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.
- hgsgm 4y agoThe meme worthy thing is thinking that, given 3 sigfig inputs, 20 sigfigs is more desirable than 3. It's failing to distinguish noise from data.
- zokier 4y agoI wonder how much confusion could have been avoided if compilers/interpreters emitted warnings for inexact float literals. It is bit surpirising pitfall, you generally expect the value of a literal to be obvious, but with floats its almost unpredictable. Similarly functions like strtod/atof could have some flags/return values indicating/preventing inexact conversions. Instead we ended up on this weird situation where values are quietly converted to something that is close to the desired value
- hgsgm 4y agoWhy bother? Almost every float literal is inexact. floats are inexact by design. That's why you can fit over 2^(2^53) values into 64 bits. And compiler can't help you on the application UI layer.
- ordu 4y ago> you generally expect the value of a literal to be obvious, but with floats its almost unpredictable Fractions in positional notations are not exact as a rule. There are some exceptions, but mostly they are not exact. 1/3, 1/6, 1/7, 1/9 cannot be represented by decimals exactly (or they can, but using infinite amount of digits in their representation). There are exceptions of course, for example for decimals you need denominator with no prime factors except 2 and 5. For binary it can be only 2.