Bi Rico
Bi Rico

Reputation: 25833

Is it possible to have two floats which fail lt, gt, and eq tests

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

Answers (1)

Artur
Artur

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:

enter image description here

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

Related Questions