This is an error of logic: the last operation 6.35 * 10.0 is innacurate rather than accurate.
It's just that it might happen that several consecutive "rounding error" annihilate, as it might also happen that they cumulate.
The nearest double to 635/100 is 635/100 - 1/2,814,749,767,106,560
Or if you prefer: 635/100 - 1/(10 * 2^48)
So an accurate *10
operation should answer 635/10 - 1/(2^48)
.
But this quantity is not representable as double precision (see below)...
So the last operation is innacurate.
The two neighbours are 63.5 (which is exactly 635/10
) and its predecessor 635/10 - 1/(2^47)
.
An interesting case of exact tie: the exact quantity is at same distance of the two representable double neighbours, The default rounding mode is round to nearest, tie to even, so the FPU will choose the double with even significand, that is 635/10
.
Is this luck or is it a nice property of IEEE 754 arithmetic?
If I evaluate this snippet in Squeak/Pharo Smalltalk (which have exact fraction and comparison of exact arithmetic values):
(1 to: 10000) count: [:x | (x/10.0) = (x/10) and: [(x/100.0) ~= (x/100)]].
I get 1600 cases where the x/10 is exactly representable as double, while x/100 is not.
If I select those 1600 cases, and verify if rounding error annihilates:
((1 to: 10000) select: [:x | (x/10.0) = (x/10) and: [(x/100.0) ~= (x/100)]])
count: [:x | (x/100.0*10) = (x/10)]
I count 1600 cases out of the 1600 for which the error annihilate, so it is a nice property of IEEE754 arithmetic. But this is still luck.
If I retry by dividing by 1000.0 then multiply by 100, I get a false answer to this question:
((1 to: 10000) select: [:x | (x/10.0) = (x/10) and: [(x/1000.0) ~= (x/1000)]])
allSatisfy: [:x | (x/1000.0*100) = (x/10)]
The answer is true for 1649 cases out of the 1920, which is already a good score.