Why do these two floating-point comparisons give different results?
fmt.Println(0.1+0.2 == 0.3) // true
a, b := 0.1, 0.2
fmt.Println(a+b == 0.3) // false
fmt.Println(a + b) // 0.30000000000000004
const huge = 1e1000 // fine as an untyped constant
fmt.Println(huge / 1e999) // 10
Untyped constant expressions are evaluated exactly at compile time, with at least 256-bit precision and effectively rational arithmetic for these literals. 0.1+0.2 is exactly 0.3 before it is ever converted to float64, so the first comparison is true.
Once the values are stored in float64 variables, each is rounded to the nearest binary double, and IEEE-754 addition gives 0.30000000000000004. That does not equal the double closest to 0.3, so the second comparison is false. huge cannot fit in any float type, but that only matters if it is converted. The quotient 10 fits, so the code compiles.
Takeaways: never compare floats with ==. Compare with a tolerance (math.Abs(a-b) <= eps*math.Max(math.Abs(a), math.Abs(b))). Never use floats for money; use integer cents or a decimal library. Also remember NaN != NaN, which makes a NaN map key impossible to look up again.
More on Tricky Output & Code-Review Puzzles
- Q504A deferred function panics while another panic is in progress. What prints?
- Q505What does this integer puzzle print?
- Q507What does indexing and ranging over a UTF-8 string print?
- Q508This compiles. Why does it panic at runtime?
- Q509Why does errors.Is return different results here?
- Q510Go 1.23 range-over-func: what does this buggy iterator do?