Python: max/min builtin functions depend on parameter order
Solution 1:
In [19]: 1>float('nan')
Out[19]: False
In [20]: float('nan')>1
Out[20]: False
The float nan
is neither bigger nor smaller than the integer 1
.
max
starts by choosing the first element, and only replaces it when it finds an element which is strictly larger.
In [31]: max(1,float('nan'))
Out[31]: 1
Since nan
is not larger than 1, 1 is returned.
In [32]: max(float('nan'),1)
Out[32]: nan
Since 1 is not larger than nan
, nan
is returned.
PS. Note that np.max
treats float('nan')
differently:
In [36]: import numpy as np
In [91]: np.max([1,float('nan')])
Out[91]: nan
In [92]: np.max([float('nan'),1])
Out[92]: nan
but if you wish to ignore np.nan
s, you can use np.nanmax
:
In [93]: np.nanmax([1,float('nan')])
Out[93]: 1.0
In [94]: np.nanmax([float('nan'),1])
Out[94]: 1.0
Solution 2:
I haven't seen this before, but it makes sense. Notice that nan
is a very weird object:
>>> x = float('nan')
>>> x == x
False
>>> x > 1
False
>>> x < 1
False
I would say that the behaviour of max
is undefined in this case -- what answer would you expect? The only sensible behaviour is to assume that the operations are antisymmetric.
Notice that you can reproduce this behaviour by making a broken class:
>>> class Broken(object):
... __le__ = __ge__ = __eq__ = __lt__ = __gt__ = __ne__ =
... lambda self, other: False
...
>>> x = Broken()
>>> x == x
False
>>> x < 1
False
>>> x > 1
False
>>> max(x, 1)
<__main__.Broken object at 0x024B5B50>
>>> max(1, x)
1
Solution 3:
Max works the following way:
The first item is set as maxval and then the next is compared to this value. The comparation will always return False:
>>> float('nan') < 1
False
>>> float('nan') > 1
False
So if the first value is nan, then (since the comparation returns false) it will not be replaced upon the next step.
OTOH if 1 is the first, the same happens: but in this case, since 1 was set, it will be the maximum.
You can verify this in the python code, just look up the function min_max in Python/bltinmodule.c