2010-02-11 12 views
5

Quando si confronta per l'uguaglianza, è corretto usare ==?Quando si confronta per l'uguaglianza va bene usare `==`?

Ad esempio:

int a = 3; 
int b = 4; 

Se il controllo per l'uguaglianza si dovrebbe usare:

if (a == b) 
{ 
    . . . 
} 

Sarebbe il cambiamento situazione se i numeri in virgola mobile sono stati utilizzati?

+0

per intero == è sufficiente – malay

+0

E il codice con == è più pulito e più leggibile. – Igor

+8

Il secondo test è in realtà un test per la disuguaglianza. – rlbond

risposta

15

'==' è perfettamente adatto per valori interi.

È necessario non confrontare i galleggianti per l'uguaglianza; utilizzare un approccio di tolleranza:

if (fabs(a - b) < tolerance) 
{ 
    // a and b are equal to within tolerance 
} 
+0

Si prega di utilizzare fabs! il confronto con abs converte gli argomenti in int first ... il che equivale a confronti molto imprecisi. –

+3

@Michael 'abs' è sovraccarico per i tipi a virgola mobile in' cmath', non c'è alcun problema nel codice di Mitch. – AraK

+4

Uno ha bisogno di usare std :: abs, perché solo quello è sovraccarico. La funzione C :: abs non lo è. Vorrei sempre dichiarare esplicitamente lo spazio dei nomi per evitare bug difficili da debug nel caso in cui accidentalmente scelga la funzione C non sovraccaricata. – Tronic

4

Re punti mobili: sì. Non usare == per i float (o conosci ESATTAMENTE cosa stai facendo se lo fai). Piuttosto usare qualcosa come

if (fabs(a - b) < SOME_DELTA) { 
    ... 
} 

EDIT: cambiato abs() per FAB()

+0

Non userei mai == per confrontare i float. –

+0

Si prega di utilizzare fabs! il confronto con abs converte gli argomenti in int first ... il che equivale a confronti molto imprecisi. –

+1

@Mitch Wheat: Ecco perché Frank Shearar ha detto che dovresti sapere cosa fai. Se lo fai, usare == va bene. Vedi Goldbergs classy "Quello che ogni scienziato informatico dovrebbe sapere sulla matematica in virgola mobile" (http://docs.sun.com/source/806-3568/ncg_goldberg.html) –

1

Confrontando int, l'uso ==. L'utilizzo di "<" e ">" allo stesso tempo per controllare l'uguaglianza su un risultato int in un codice più lento perché richiede due confronti anziché uno, impiegando il doppio periodo di tempo. (probabilmente il compilatore lo aggiusterà per te, ma non dovresti abituarti a scrivere codice cattivo).

Ricordate, l'ottimizzazione anticipata è negativa, ma il codice precoce inefficiente è altrettanto grave.

EDIT: corretti alcuni inglese ...

+0

I downvoters si preoccupano di spiegare cosa ho detto di sbagliato? – speeder

+0

Ok, quindi abbiamo persone che hanno sviato gli altri per promuovere i loro avventurieri? Ho 2 downvotes e nessuna spiegazione, se sei un vero critico, dovresti vedere che sono newbie e dovrei sapere che non ho idea di cosa ho sbagliato, ma se non sei un vero critico, non dovrebbe andare in giro a castrare i downvotes casuali. – speeder

+1

Non ho fatto un downvote, ma l'affermazione di due confronti che producono codice più lento è molto falsa, in quanto i compilatori (come dici tu) lo ottimizzano comunque. – Tronic

2

In molte classi, operator== è tipicamente implementato come (!(a < b || b < a)), così si dovrebbe andare avanti e usare ==. Tranne i galleggianti, come ha detto Mitch Wheat in alto.

+1

Sono sorpreso che un singolo operatore sarebbe implementato in termini di 3 operatori in molti casi. E se viene tipicamente implementato come sopra, va ben oltre spiegando perché l'universo è così incasinato: "a Duncan

+0

Non ho mai visto un compilatore che genera codice per '==' usa qualcosa di diverso da una singola istruzione di confronto. Se capisco correttamente, stai dicendo che fa due confronti e controlla non per "uguaglianza" ma una coppia di meno di? – wallyk

+1

rlbond non sta parlando di tipi built-in, ma di classi utente. L'operatore di scrittura == in questo modo è in effetti tipico, perché l'opearator di confronto "standard" in C++ è operatore <, se non altro perché questo è ciò che utilizza l'STL. Quindi scrivere altri operatori di confronto in termini di operatore <è una buona pratica. – Gorpik

1

Per numeri interi, == fa esattamente quello che ti aspetti. Se sono uguali, sono uguali.

Per i galleggianti, è un'altra storia. Le operazioni producono risultati imprecisi e gli errori si accumulano. Devi essere un po 'confuso quando si tratta di numeri. Io uso

if (std::abs(a - b) 
    < std::abs(a) * (std::numeric_limits<float_t>::epsilon() * error_margin)) 

dove float_t è un typedef; questo mi dà la massima precisione possibile (supponendo che error_margin sia stato calcolato correttamente) e consenta una facile regolazione ad un altro tipo.

Inoltre, alcuni valori a virgola mobile non sono numeri: c'è infinito, meno infinito e ovviamente non un numero. == fa cose divertenti con quelli. L'infinito è uguale a infinito, ma il non-a-numero non è uguale a un numero.

Infine, ci sono zero positivi e negativi, che sono distinti ma uguali tra loro! Per separarli, devi fare qualcosa come controllare se l'inverso è infinito positivo o negativo. (Assicurati solo di non avere un'eccezione divisa per zero.)

Quindi, a meno che non si dispone di una domanda più specifica, spero che lo gestisce ...

+0

Non è una buona idea se a è negativo. try std :: abs (a-b) <(std :: abs (a) + std :: abs (b)) * .... –

+0

@ Michael: Grazie, corretto. Non è necessario aggiungerli all'RHS, poiché il confronto sarebbe falso se facesse la differenza. La differenza tra epsilon * (a + a) ed epsilon * (a + b) è inferiore alla precisione di a-b, altrimenti error_margin deve essere scelto abbastanza basso da consentire il confronto. Forse aggiungere un + b è importante se stai filtrando più della metà dei bit della mantissa ... in ogni caso è necessaria un'analisi del calcolo effettivo. – Potatoswatter

+0

Il problema che ho con il tuo metodo di confronto aggiornato è che non è simmetrico. , ad esempio è possibile confrontare (a, b)! = Confronta (b, a) quando b-a è vicino alla tolleranza scalata. Non mi piace questa possibilità. –

2

Facendo < e> i confronti in realtà non vi aiuterà con errori di arrotondamento. Usa la soluzione fornita da Mark Shearar. I confronti diretti di uguaglianza per i galleggianti non sono sempre cattivi, però. Puoi usarli se qualche valore specifico (ad es. 0.0 o 1.0) è direttamente assegnato a una variabile, per verificare se la variabile ha ancora quel valore. È solo dopo i calcoli in cui gli errori di arrotondamento avvitano i controlli di uguaglianza.

Si noti che il confronto di un valore NaN con qualsiasi valore (anche un altro NaN) con <,>, < =,> = o == restituisce false. ! = restituisce true.

+0

Mark Shearar non ha partecipato a questa discussione –

+0

@phresnel: se intendi che ha scambiato "Mark" per "Frank", OK, lascia vivere il ragazzo ... – Gorpik

+0

@Gorpik: ovviamente, questo non era inteso come un insulto o così :) –

Problemi correlati