Domanda

So che non puoi fare affidamento sull'uguaglianza tra valori di tipo doppio o decimale normalmente, ma mi chiedo se 0 è un caso speciale.

Anche se riesco a capire le imprecisioni tra 0,00000000000001 e 0,00000000000002, lo stesso 0 sembra piuttosto difficile da confondere poiché non è proprio niente. Se sei impreciso sul nulla, non è più niente.

Ma non so molto su questo argomento, quindi non spetta a me dirlo.

double x = 0.0;
return (x == 0.0) ? true : false;

Restituirà sempre vero?

È stato utile?

Soluzione

È sicuro aspettarsi che il confronto restituisca true se e solo se la doppia variabile ha un valore esattamente 0.0 (che nello snippet di codice originale è, ovviamente, il caso). Ciò è coerente con la semantica dell'operatore ==. a == b significa " a è uguale a b " ;.

È non sicuro (perché è non corretto ) aspettarsi che il risultato di alcuni calcoli sarà zero in aritmetica doppia (o più in generale, in virgola mobile) ogni volta che il risultato dello stesso calcolo in matematica pura è zero. Questo perché quando i calcoli entrano nel terreno, appare un errore di precisione in virgola mobile - un concetto che non esiste nell'aritmetica dei numeri reali in matematica.

Altri suggerimenti

Se devi fare molto " uguaglianza " confronti potrebbe essere una buona idea scrivere una piccola funzione di supporto o un metodo di estensione in .NET 3.5 per confrontare:

public static bool AlmostEquals(this double double1, double double2, double precision)
{
    return (Math.Abs(double1 - double2) <= precision);
}

Questo potrebbe essere usato nel modo seguente:

double d1 = 10.0 * .1;
bool equals = d1.AlmostEquals(0.0, 0.0000001);

Per il tuo semplice esempio, quel test va bene. Ma che dire di questo:

bool b = ( 10.0 * .1 - 1.0 == 0.0 );

Ricorda che .1 è un decimale ripetuto in binario e non può essere rappresentato esattamente. Quindi confrontalo con questo codice:

double d1 = 10.0 * .1; // make sure the compiler hasn't optimized the .1 issue away
bool b = ( d1 - 1.0 == 0.0 );

Ti lascio eseguire un test per vedere i risultati effettivi: è più probabile che tu lo ricordi in questo modo.

Dalla voce MSDN per Double.Equals :

  

Precisione nei confronti

     

Il metodo Equals dovrebbe essere usato con   attenzione, perché due apparentemente   valori equivalenti possono essere ineguali   alla diversa precisione dei due   valori. Il seguente esempio riporta   che il doppio valore .3333 e il   Il doppio restituito dividendo 1 per 3 sono   disuguale.

     

...

     

Anziché confrontare per l'uguaglianza,   una tecnica consigliata prevede   la definizione di un margine accettabile di   differenza tra due valori (come   .01% di uno dei valori). Se la   valore assoluto della differenza   tra i due valori è minore di o   uguale a quel margine, la differenza   è probabilmente dovuto alle differenze di   precisione e, quindi, i valori   sono probabilmente uguali. Il seguente   esempio usa questa tecnica per confrontare   .33333 e 1/3, i due valori Double   che ha trovato l'esempio di codice precedente   essere disuguale.

Inoltre, vedi Double.Epsilon .

Il problema si presenta quando si confrontano diversi tipi di implementazione del valore in virgola mobile, ad es. confrontando float con double. Ma con lo stesso tipo, non dovrebbe essere un problema.

float f = 0.1F;
bool b1 = (f == 0.1); //returns false
bool b2 = (f == 0.1F); //returns true

Il problema è che il programmatore a volte dimentica che il cast di tipo implicito (double to float) sta accadendo per il confronto e si traduce in un bug.

Se il numero è stato assegnato direttamente al float o al double, allora è sicuro testare contro zero o qualsiasi numero intero che può essere rappresentato in 53 bit per un double o 24 bit per un float.

Oppure, per dirla in un altro modo, puoi sempre assegnare un valore intero a un doppio, quindi confrontare il doppio ritorno con lo stesso numero intero e assicurarti che sarà uguale.

Puoi anche iniziare assegnando un numero intero e fare in modo che i semplici confronti continuino a funzionare attenendosi all'aggiunta, alla sottrazione o alla moltiplicazione per numeri interi (supponendo che il risultato sia inferiore a 24 bit per un float e 53 bit per un doppio) . Quindi puoi trattare float e doppi come numeri interi in determinate condizioni controllate.

No, non è OK. I cosiddetti valori denormalizzati (subnormali), se confrontati con 0,0, comparerebbero come falsi (diversi da zero), ma se usati in un'equazione verrebbero normalizzati (diventano 0,0). Pertanto, l'utilizzo di questo come meccanismo per evitare una divisione per zero non è sicuro. Invece, aggiungi 1.0 e confronta con 1.0. Questo assicurerà che tutti i subnormali siano trattati come zero.

Prova questo e scoprirai che == non è affidabile per double / float.
double d = 0.1 + 0.2; bool b = d == 0.3;

Ecco il rispondi di Quora.

In realtà, penso che sia meglio usare i seguenti codici per confrontare un doppio valore con 0,0:

double x = 0.0;
return (Math.Abs(x) < double.Epsilon) ? true : false;

Lo stesso per float:

float x = 0.0f;
return (Math.Abs(x) < float.Epsilon) ? true : false;
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top