Using math.Float32bits
and math.Float64bits
, you can see how Go represents the different decimal values as a IEEE 754 binary value:
Playground: https://play.golang.org/p/ZqzdCZLfvC
Result:
float32(0.1): 00111101110011001100110011001101
float32(0.2): 00111110010011001100110011001101
float32(0.3): 00111110100110011001100110011010
float64(0.1): 0011111110111001100110011001100110011001100110011001100110011010
float64(0.2): 0011111111001001100110011001100110011001100110011001100110011010
float64(0.3): 0011111111010011001100110011001100110011001100110011001100110011
If you convert these binary representation to decimal values and do your loop, you can see that for float32, the initial value of a
will be:
0.20000000298023224
+ 0.10000000149011612
- 0.30000001192092896
= -7.4505806e-9
a negative value that can never never sum up to 1.
So, why does C behave different?
If you look at the binary pattern (and know slightly about how to represent binary values), you can see that Go rounds the last bit while I assume C just crops it instead.
So, in a sense, while neither Go nor C can represent 0.1 exactly in a float, Go uses the value closest to 0.1:
Go: 00111101110011001100110011001101 => 0.10000000149011612
C(?): 00111101110011001100110011001100 => 0.09999999403953552
Edit:
I posted a question about how C handles float constants, and from the answer it seems that any implementation of the C standard is allowed to do either. The implementation you tried it with just did it differently than Go.
a
to have a non-zero (albeit very small) value before entering the loop. Wikipedia has an explanation. en.wikipedia.org/wiki/Guard_digitgo tool 6g -S main.go
you will see the reason. The calculation for float32 is as follows: 2.00000002980232230e-01 + 1.00000001490116120e-01 - 3.00000011920928950e-01 which is a negative value and will never sum up to 1. Why Go does this, I do not know.0.30...04
, you get0.30000000000000004440892098500626161694526672363281
and the rest gets cut off. I'm guessing that with a float32, a lot more gets cut off and it gets rounded to an even0.3
. This could explain the arithmetic, but right now its just a theory.