Consider the following Unit Test:
// Works (sum 0.1 to 0.4)
float f1 = 0.1F + 0.2F + 0.3F + 0.4F;
Assert.AreEqual(1F, f1);
// Works too (sum 0.4 to 0.1)
float f2 = 0.4F + 0.3F + 0.2F + 0.1F;
Assert.AreEqual(1F, f2);
// Works (sum 0.1 to 0.4)
double d1 = 0.1D + 0.2D + 0.3D + 0.4D;
Assert.AreEqual(1D, d1);
// Fails! (sum 0.4 to 0.1)
double d2 = 0.4D + 0.3D + 0.2D + 0.1D;
Assert.AreEqual(1D, d2);
Everything works as expected for the float type (the sum is 1 in both cases), but when using double, the commutativity of the addition is not honored. Indeed, the sum of the first one is 1, but for the second I get 0.99999999.....
I understand why the result is once 1 and once not (because some numbers cannot be represented without loss of precision in base 2) but this does not explain why it works for float and not for double...
Could someone explain this?
float f11 = 0;
f11 += 0.1F;//0.1
f11 += 0.2F;//0.3
f11 += 0.3F;//0.6
f11 += 0.4F;//1.0
float f2 = 0.4F + 0.3F + 0.2F + 0.1F;
float f22 = 0;
f22 += 0.4F;//0.4
f22 += 0.3F;//0.700000048
f22 += 0.2F;//0.900000036
f22 += 0.1F;//1.0
To add to astander's answer - this is how values looks for floats. Due to lower precision (7 digits for floats, 14-15 for doubles) values ends up being displayed differently and accidentally equal to what you expected.
But that's it - it's just coincidence! Never depend on it. Floating point operations are associative, nor precise. Never compare floats or doubled using ==
, always consider using some margin value. This sample works for 1
, but for other value it will surly fail.