2012-07-10 8 views
15

ho una stringa che converte ad una doppia come questo:"-Weverything" cedendo "Confronto in virgola mobile con == o = non è sicuro!"

double d = [string doubleValue]; 

La documentazione per doubleValue ci dice che su di trabocco , questo metodo restituisce HUGE_VAL o -HUGE_VAL. Questo è il modo che ho controllato per questo in precedenza:

if (d == HUGE_VAL || d == -HUGE_VAL) 
    //overflow 

Ora, dal momento che l'aggiunta del nuovo "-Weverything" bandiera di avvertimento, il compilatore ora lamenta che

Comparing floating point with == or != is unsafe 

Come posso risolvere questo problema? Come dovrei sto facendo questi confronti?


Ho anche la stessa domanda sul confronto di due numeri in virgola mobile "normali" (cioè non "HUGE_VAL" quelli). Ad esempio,

double a, b; 
//... 
if (a != b) //this will now yield the same warning 
    //... 

Come dovrebbe essere risolto?

risposta

29

Non è necessario preoccuparsi di questo avviso. Non ha senso in molti casi, incluso il tuo.

La documentazione di doubleValue non dice che restituisce qualcosa abbastanza vicino a HUGE_VAL o -HUGE_VAL in overflow. Dice che restituisce esattamente questi valori in caso di overflow.

In altre parole, il valore restituito dal metodo in caso di overflow confronta == a HUGE_VAL o -HUGE_VAL.

Perché l'avviso esiste in primo luogo?

Considerare l'esempio 0.3 + 0.4 == 0.7. Questo esempio restituisce false. Le persone, inclusi gli autori dell'avvertimento che hai incontrato, pensano che il numero a virgola mobile == sia impreciso e che il risultato imprevisto derivi da questa inaccuratezza.

Sono tutti sbagliati.

virgola mobile, è "inaccurato", per alcuni sensi imprecisi: restituisce il numero a virgola mobile rappresentabile più vicino per l'operazione richiesta. Nell'esempio sopra, le conversioni (da decimale a virgola mobile) e l'aggiunta a virgola mobile sono le cause dello strano comportamento.

virgola mobile uguaglianza, d'altra parte, funziona praticamente esattamente come per altri tipi discreti.L'uguaglianza in virgola mobile è esatta: tranne per le eccezioni minori (il valore NaN e il caso di +0. E -0.), L'uguaglianza viene valutata su true se e solo se i due numeri in virgola mobile in considerazione hanno la stessa rappresentazione.

Non è necessario un epsilon per verificare se due valori in virgola mobile sono uguali. E, come Dewar says in substance, l'avvertimento nell'esempio 0.3 + 0.4 == 0.7 dovrebbe essere su +, non su ==, per l'avvertimento di senso.

Infine, confrontando con un'approssimazione epsilon significa che i valori non sono uguali sembreranno uguali, che non è appropriato per tutti gli algoritmi.

+0

Ha senso. D'altra parte, sembra anche sensato avvertire su questo, in qualche modo. C'è un modo per dire al compilatore in modo più esplicito che: "Sì, sono assolutamente sicuro che sto confrontando questi float come esattamente uguali tra loro e non mi avvisano". ? Quindi, nei casi in cui sono sicuro, l'avviso non verrà visualizzato. In altri casi, farei il test epsilon. – NoobOverflow

+0

@NoobOverflow Se vuoi davvero rendere felice il compilatore, verifica se 'd> = HUGE_VAL || d <= -HUGE_VAL'. Calcola la stessa cosa senza usare '=='. Ma mi raccomando di non usare l'avvertimento. –

+0

@NoobOverflow In realtà, la mia precedente raccomandazione rende il codice meno leggibile, ma se Objective-C ha una funzione 'is_infinity', l'uso di questo renderebbe il codice ** più ** leggibile. La specifica della funzione dovrebbe essere che ritorna true esattamente per i due valori 'HUGE_VAL' e' -HUGE_VAL', e ti consiglio di usarlo solo per quello. –

-1

I galleggianti non devono essere confrontati con == o! = A causa di inaccuratezza del tipo float, che potrebbe causare errori imprevisti durante l'utilizzo di questi operatori. Dovresti testare se i galleggianti si trovano a una distanza l'uno dall'altro (chiamato "Epsilon" il più delle volte).

Potrebbe assomigliare a questo:

const float EPSILON = 1.0f; // use a really small number instead of this 

bool closeEnough(float f1, float f2) 
{ 
    return fabs(f1-f2)<EPSILON; 
    // test if the floats are so close together that they can be considered equal 
} 
+1

Cosa epsilon può essere raccomandato? Questo approccio funzionerà anche con quegli HUGE_VAL? E la tua risposta implica che il commento di Pascal sopra non è corretto? – NoobOverflow

+0

Inoltre, non esiste una funzione integrata di questo tipo che possa essere utilizzata? È un po 'un peccato che io tocchi la mia funzione personalizzata in qualche luogo globale. – NoobOverflow

+0

Pascal ha ragione, probabilmente non dovrai preoccuparti di questo avviso. V'è un built-in Epsilon, però, un'occhiata a [questo] (http://www.cplusplus.com/reference/std/limits/numeric_limits/) – Brainbot

8

In questo caso, provare a utilizzare >= e <=.

+3

Perché è meglio? –

+3

Beh, non confronta per l'uguaglianza rigorosa, quindi pacifica il compilatore.E poiché nulla può essere maggiore di HUGE_VAL o inferiore a -HUGE_VAL, funziona allo stesso modo. – echristopherson

2

Se sei sicuro della tua confronto e si vuole dirgli di clang, circondare il codice con:

#pragma clang diagnostic ignored "-Wfloat-equal" 
/* My code triggering the warnings */ 
#pragma clang diagnostic pop