2014-09-29 3 views
12

Sto solo rivedendo alcune nozioni di base su Python e c'è un problema difficile nel confrontare i numeri in virgola mobile.Confronto di numeri in virgola mobile in Python

2.2 * 3.0 == 6.6 
3.3 * 2.0 == 6.6 

Ho pensato che entrambi dovevano restituire un Falso. Tuttavia, il secondo mi ha dato una verità. enter image description here

Please help me here. Grazie!

+10

Non confrontare mai due numeri in virgola mobile con '=='. Usa 'abs (a-b) Steve

+0

@Steve Sì, ne sono consapevole, ma grazie ancora per la nota :) – Zhiya

+3

@Steve: un confronto corretto è più complicato di questo, poiché la precisione dei float è un numero di cifre, non un valore numerico assoluto. Qualcosa come 'abs (a-b) <= rel_prec * max (abs (a), abs (b))' è migliore (con rel_prec vicino a 1e-16, ad esempio, per i float a doppia precisione di Python). Oltre a questo, dovrebbe essere gestito anche il caso di un valore zero. Non ho controllato completamente questo, ma il seguente potrebbe funzionare: 'abs (a-b) <= rel_prec * (max (abs (a), abs (b)) if a! = 0! = B else 1)'. – EOL

risposta

11

questo potrebbe essere illuminante:

>>> float.hex(2.2 * 3.0) 
'0x1.a666666666667p+2' 
>>> float.hex(3.3 * 2.0) 
'0x1.a666666666666p+2' 
>>> float.hex(6.6) 
'0x1.a666666666666p+2' 

Anche se sono tutti visualizzati in decimale come 6.6, quando si controlla la rappresentazione interna, due dei quali sono rappresentati allo stesso modo, mentre uno di loro non è.

+1

Ma non sono tutti visualizzati in decimale come '6.6'. In 3.x, 'print (2.2 * 3.0)' o solo '2.2 * 3.0' mostrerà' 6.6000000000000005'. In 2.x, 'print' troncherà, ma solo' 2.2 * 3.0' mostrerà '6.6000000000000005'. Quindi, è più semplice da vedere rispetto alla risposta. – abarnert

+0

@abarnert: Ah, giusto. Presumo, non ho controllato. – Amadan

2

Per completare la buona risposta di Amadan, ecco un modo più ovvio di vedere 2.2 * 3. e 3.3 * 2. non sono rappresentati dallo stesso float: in un guscio pitone,

>>> 2.2 * 3. 
6.6000000000000005 
>>> 3.3 * 2. 
6.6 

Infatti, la shell Python visualizza la rappresentazione di numeri, che per definizione dovrebbe consentire corrispondente galleggiante sia correttamente ricostruito dalla rappresentazione , quindi vedi l'approssimazione numerica di 2.2 * 3 che Python fa. Il fatto che 2.2 * 3. ! = 3.3 * 2. è ovvio quando si visualizzano tutte le cifre necessarie, come sopra.

+0

La parte relativa alla rappresentazione rispetto alla versione amichevole è rilevante per Python 2.x, ma non per 3.x. In 3.x, 'print (2.2 * 3.)' Ti darà comunque '6.6000000000000005'. In 3.x, sia 'str' che' repr' restituiscono la stringa più breve che valuterà lo stesso 'float'; in 2.x, 'str' tronca su un numero specifico di piattaforme, mentre' repr' no. – abarnert

+0

Interessante. Prima del tuo commento, però, non c'era "parte sulla rappresentazione rispetto alla versione amichevole". : D – EOL

+1

Riferimento alla modifica di 'str' di Python 3: http://stackoverflow.com/questions/25898733/why-does-strfloat-return-more-digits-in-python-3-than-python-2. – EOL