2010-11-21 10 views
45

max(float('nan'), 1) evalúa a nanPython: max/min funciones incorporadas dependen de orden de los parámetros

max(1, float('nan')) evalúa a 1

¿Es el comportamiento previsto?


Gracias por las respuestas.

max produce una excepción cuando el iterable está vacío. ¿Por qué el max de Python no generaría una excepción cuando nan está presente? O al menos hacer algo útil, como devolver nan o ignorar nan. El comportamiento actual es muy inseguro y parece completamente irracional.

Encontré una consecuencia aún más sorprendente de este comportamiento, así que acabo de publicar un related question.

+0

... Realmente no parece romper el 'nan', porque 'max (0,5, float ('nan'), 1) 'devuelve 1. – khachik

+2

@khachik: Solo digo que el resultado de 'max' depende del orden de los parámetros, lo cual es un poco inesperado para mí, incluso si solo ocurrió en un ejemplo. Pero de hecho también funciona en su ejemplo: 'max (float ('nan'), 1, 0.5)' devuelve a nan. – max

+1

El error no está en max. El error es el hecho de que estás usando puntos flotantes y asumiendo que tienen un comportamiento matemático significativo. – Antimony

Respuesta

39
In [19]: 1>float('nan') 
Out[19]: False 

In [20]: float('nan')>1 
Out[20]: False 

El flotador nan es ni mayor ni menor que el número entero 1. max comienza eligiendo el primer elemento, y solo lo reemplaza cuando encuentra un elemento que es estrictamente más grande.

In [31]: max(1,float('nan')) 
Out[31]: 1 

Desde nan no es mayor que 1, se devuelve 1.

In [32]: max(float('nan'),1) 
Out[32]: nan 

Desde 1 no es mayor que nan, se devuelve nan.


PS. Tenga en cuenta que np.max trata float('nan') de otra manera:

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 

pero si desea ignorar np.nan s, se pueden utilizar np.nanmax:

In [93]: np.nanmax([1,float('nan')]) 
Out[93]: 1.0 

In [94]: np.nanmax([float('nan'),1]) 
Out[94]: 1.0 
+6

Gracias que ayuda. Terrible comportamiento, sin embargo, IMO. – max

7

No he visto esto antes, pero tiene sentido. Observe que nan es un objeto muy raro:

>>> x = float('nan') 
>>> x == x 
False 
>>> x > 1 
False 
>>> x < 1 
False 

yo diría que el comportamiento de max no está definido en este caso - ¿qué respuesta se puede esperar? El único comportamiento sensato es suponer que las operaciones son antisimétricas.


Observe que puede reproducir este comportamiento al hacer una clase rota:

>>> 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 
+0

Para la comparación de NaN debe usar math.isnan function – Andrew

1

Max funciona de la siguiente manera:

se establece el primer elemento como maxval y luego el siguiente se compara con este valor.La comparacion siempre devolverá Falso:

>>> float('nan') < 1 
False 
>>> float('nan') > 1 
False 

Así que si el primer valor es NaN, entonces (ya que la comparacion devuelve falso) no va a ser reemplazado en el siguiente paso.

OTOH si 1 es el primero, pasa lo mismo: pero en este caso, como 1 fue configurado, será el máximo.

Esto se puede comprobar en el código Python, basta con ver el min_max función en Python/bltinmodule.c

Cuestiones relacionadas