2011-08-24 7 views
24

Ho il codice seguente:La verifica di un doppio per l'uguaglianza è sempre sicura?

double x = 0; 

{ ...do stuff ...} 

if(x == 0){ 

} 

Sono sempre stato insegnato che non si dovrebbe verificare galleggianti per l'uguaglianza. Sta controllando per vedere se è uguale a zero qualsiasi diverso?

+0

non capisco, se si avvia x a 0 perché non è bene controllare se 0? 0 è un valore valido per il doppio – JohnJohnGa

+1

I numeri in virgola mobile hanno un sacco di arrotondamenti quando si inizia a raggiungere i limiti. La stessa ragione per cui se hai 3 cifre da usare in base dieci, hai .004 e dividi per tre, ti aspetti .001, ma chissà cosa succede. –

+0

Correzioni di Thomas: tecnicamente non è arrotondato, ma inesattezza a causa della precisione limitata e della natura binaria dei galleggianti. –

risposta

27

Il motivo per cui non è necessario controllare i float per l'uguaglianza è che i numeri in virgola mobile non sono perfettamente precisi - c'è qualche inaccuratezza nella memorizzazione con alcuni numeri, come quelli che si estendono troppo nella mantissa e ripetono i decimali (nota che Sto parlando della ripetizione dei decimali nella base 2). Puoi pensare a questa imprecisione come "arrotondando per difetto". Le cifre che si estendono oltre la precisione del numero in virgola mobile vengono troncate, arrotondando effettivamente verso il basso.

Se non è stato modificato, manterrà tale uguaglianza. Tuttavia, se lo modifichi anche leggermente, probabilmente non dovresti usare le uguaglianze, ma piuttosto un intervallo come (x < 0.0001 && x > -.0001).

In breve: finché non stai giocando con x a un livello molto piccolo, è OK.

+6

Non è in corso l'arrotondamento, ma l'impossibilità di memorizzare determinati numeri a causa della rappresentazione di numeri in virgola mobile. 0 può essere rappresentato esattamente da un valore in virgola mobile, ma non tutti i valori possono. 0.1, ad esempio, deve essere approssimato. –

+1

@Thomas Arrotondare. La stessa ragione per cui '3/2' è' 1' –

+7

No, non arrotondando. Imprecisioni nelle rappresentazioni in virgola mobile IEEE. Non ha assolutamente nulla a che fare con l'arrotondamento. http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems –

16

È sicuro che lo 0 che stai cercando di catturare sia lo 0 originale impostato all'inizializzazione. Tuttavia, non è sicuro se ti aspetti uno 0 da un'operazione matematica.

+0

quale dovrebbe essere l'approccio giusto quando si desidera confrontare 0 dall'operazione matematica –

+0

Vedere la risposta accettata. – Vache

4

Ancora non si dovrebbe verificare se è uguale a zero. Controlla per vedere se è vicino allo zero.

private final static double EPSILON = 0.00001; 
if (x + EPSILON > 0 && x - EPSILON < 0){ 
... 
} 
+3

Non si dovrebbe usare un'epison assoluta ma una relativa. E.G., 'if (value> = target * (1 - epsilon) && value <= target * (1 + epsilon))' Questo è particolarmente vero quando i valori possono variare su un ampio intervallo. –

+2

@HovercraftFullOfEels Funzionerà solo se l'obiettivo è positivo. –

4

se si imposta da soli e volete vedere se mai cambiato è possibile controllare in modo sicuro per l'uguaglianza (come l'utilizzo di un valore sentinella) se NaN è più sicuro per cose del genere

float x=Float.NaN; 
{ 
    //some code that may or may not set x 
} 
if(Float.isNaN(x))//it never got set 
2

doppia ha zero positivo e negativo. == tra zero positivo e zero negativo restituisce falso. Inoltre, == tra due NaN restituisce false.

Problemi correlati