2010-11-21 8 views
45

max(float('nan'), 1) viene valutato come nanPython: funzioni built-max/min dipendono ordine parametro

max(1, float('nan')) viene valutata a 1

E 'il comportamento previsto?


Grazie per le risposte.

max genera un'eccezione quando l'iterabile è vuoto. Perché Python non ha rilevato un'eccezione con max quando è presente nan? O almeno fare qualcosa di utile, come restituire nan o ignorare nan. Il comportamento attuale è molto pericoloso e sembra completamente irragionevole.

Ho trovato una conseguenza ancora più sorprendente di questo comportamento, quindi ho appena pubblicato un related question.

+0

Davvero ... non sembra rompere il 'nan', perché 'max (0.5, float ('nan'), 1) 'restituisce 1. – khachik

+2

@khachik: Sto solo dicendo che il risultato' max' dipende dall'ordine dei parametri, che per me è un po 'inaspettato, anche se è successo solo in un esempio. Ma in effetti funziona anche sul tuo esempio: 'max (float ('nan'), 1, 0.5)' restituisce nan. – max

+1

Il bug non è nel massimo. Il bug è il fatto che stai usando punti fluttuanti e assumendo che abbiano un comportamento matematico significativo. – Antimony

risposta

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

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

Il galleggiante nan non è né più grande né più piccolo il numero intero 1. max inizia scegliendo il primo elemento e lo sostituisce solo quando trova un elemento che è strettamente più grande.

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

Dal nan non è maggiore di 1, 1 viene restituito.

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

Dal 1 non è più grande di nan, nan viene restituito.


PS. Si noti che np.max tratta float('nan') diversamente:

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 

, ma se si vuole ignorare np.nan s, è possibile utilizzare 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

Grazie che aiuta. Comportamento terribile, però, IMO. – max

7

Non l'ho mai visto prima, ma ha senso. Si noti che nan è un oggetto molto strano:

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

Direi che il comportamento della max non è definito in questo caso - che risposta ci si può aspettare? L'unico comportamento ragionevole è di supporre che le operazioni siano antisimmetriche.


Si noti che è possibile riprodurre questo comportamento facendo una classe di rotta:

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

Per il confronto NaN è necessario utilizzare la funzione math.isnan – Andrew

1

Max funziona nel seguente modo:

La prima voce è impostata come maxval e poi il prossimo viene confrontato con questo valore.La comparazione restituisce sempre False:

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

Quindi, se il primo valore è nan, poi (dal momento che la comparazione restituisce false) non sarà sostituito sopra il passo successivo.

OTOH se 1 è il primo, succede lo stesso: ma in questo caso, poiché è stato impostato 1, sarà il massimo.

Lo si può verificare nel codice Python, basta guardare la funzione min_max in Python/bltinmodule.c

Problemi correlati