Reputation: 25833
I have a block of code that looks something like this:
if a > b:
pass
elif a < b:
pass
elif a == b:
pass
else:
# Can I assume that a or b is nan if I'm here?
I want to know if reaching the final else block necessarily implies that either a or b is nan. Is there any other way to have two floats that fail the first three comparisons?
Upvotes: 1
Views: 250
Reputation: 7267
IEEE 754 standard says:
5.7. Comparison It shall be possible to compare floating-point numbers in all supported formats, even if the operands' formats differ. Comparisons are exact and never overflow nor underflow. Four mutually exclusive relations are possible: less than, equal, greater than, and unordered. The last case arises when at least one operand is NaN. Every NaN shall compare unordered with everything, including itself.
It means that if any or both comparison operands are NaNs - result os >, <, == will be false.
Since Python adheres to IEE754 standard you can safely assume that if at least one of your operands to (<,>,==) is NaN you'll end up in else statement.
You can verify that of course:
import math
nan = float("nan")
a_and_b = [ (1.0, 3.0), (3.0, nan), (nan, 3.0), (nan, nan)]
for (a,b) in a_and_b:
print("a={} b={}".format(a,b))
if a > b:
print(' a>b')
elif a < b:
print(' a<b')
elif a == b:
print(' a==b')
else:
print(' else')
yields:
a=1.0 b=3.0
a<b
a=3.0 b=nan
else
a=nan b=3.0
else
a=nan b=nan
else
Since most of PCs have x87 FPU all floating point comparisons are accomplished by FCOM-like coprocessor instruction which results in setting 4 bits (C0..C3) is comprocessor's status word depending on result. Documentation excerpt:
On low level - after comparing 2 floats your program fetches FPU's status word and based on these 3 of 4 status flags decides what to do. Since at least one of your comparison arguments will be NaN you'll end up in the last case (unordered) and as I've already mentioned none of (>, <, ==) will return true hence you end up in your else statement
Upvotes: 2