Before you link me to Is floating point math broken? - please read the question first. I'm aware how this works. The question is specific to the two numbers I've found (well, presumably a lot more such pairs exist, but I would like this specific behavior to be explained).
I have two floating point constants: 1.9
and 1.1
. Using Python, I've multiplied both of these by their reciprocals and got the following results:
>>> x = 1.1
>>> y = 1.9
>>> print("%.55f" % x)
1.1000000000000000888178419700125232338905334472656250000
>>> print("%.55f" % y)
1.8999999999999999111821580299874767661094665527343750000
>>> print("%.55f" % (1/x))
0.9090909090909090606302811465866398066282272338867187500
>>> print("%.55f" % (1/y))
0.5263157894736841813099204046011436730623245239257812500
>>> print("%.55f" % ((1/x) * x))
1.0000000000000000000000000000000000000000000000000000000
>>> print("%.55f" % ((1/y) * y))
0.9999999999999998889776975374843459576368331909179687500
I'm of course aware of the issues with floating-point arithmetic as implemented in hardware, but I cannot understand why these numbers show such different behavior. Consider their reciprocals; their exact results as follows (computed using WolframAlpha, later digits omitted for brevity):
1/x
:0.909090909090909017505915727262383419481191148103102677263...
1/y
:0.526315789473684235129596113576877392185605155259237553584...
Clearly the reciprocals computed by my hardware are correct until around the 15th-16th decimal digit for both numbers; no difference there. What else could be different? How is it possible that (1/x) * x
is exactly 1
, without any "garbage" at the end?
For the sake of completeness I should perhaps mention that I'm on an x86 PC, so this is all 64-bit IEEE 754 arithmetic:
>>> sys.float_info
sys.float_info(max=1.7976931348623157e+308, max_exp=1024, max_10_exp=308, min=2.2250738585072014e-308, min_exp=-1021, min_10_exp=-307, dig=15, mant_dig=53, epsilon=2.220446049250313e-16, radix=2, rounds=1)