2009-10-30 3 views

risposta

44

In realtà non è possibile confrontare i valori in virgola mobile e integrale in modo ingenuo; in particolare, dal momento che c'è il classico floating pointrepresentation challenges. Quello che possibile fare è sottrarre l'uno dall'altro e vedere se la differenza tra loro è inferiore a una certa precisione che ti interessano, in questo modo:

int iValue = 0; 
double dValue = 0.0; 

var diff = Math.Abs(dvalue - iValue); 
if(diff < 0.0000001) // need some min threshold to compare floating points 
    return true; // items equal 

Bisogna davvero definire da soli ciò che equality significa per voi . Ad esempio, potresti volere che un valore in virgola mobile torni verso il numero intero più vicino, in modo che 3.999999981 sia "uguale" a 4. Oppure potresti troncare il valore, in modo che sia effettivamente 3. Tutto dipende da ciò che stai cercando di ottenere.

MODIFICA: Nota che ho scelto 0,0000001 come valore di soglia di esempio ... è necessario decidere autonomamente quale precisione è sufficiente per il confronto. Basta rendersi conto che è necessario essere entro i limiti di rappresentazione normale di double che credo sia definito come Double.Espilon.

+0

Questa è una bella soluzione al problema che ho citato. Per una maggiore precisione (solo quando è necessario), utilizzare solo numeri interi, come ho suggerito nella mia risposta. –

+0

Sarebbe meglio confrontare con il sistema epsilon costante definito (vedi qui http://msdn.microsoft.com/en-us/library/system.double.epsilon.aspx) invece di un valore codificato come 0.0000001? NB Non ho mai codificato C# (solo C++) ma presumo lo stesso principio si applica – pxb

+1

Lo menziono nella modifica alla mia risposta. Epsilon può o non può essere una buona scelta a seconda della precisione che l'OP ha a cuore nel suo codice. – LBushkin

1

Questo dipende molto da quello che consideri "uguale". Se si desidera che il confronto per ritornare vero se e solo se il doppio corrisponde con precisione il valore intero (cioè non ha nessun componente frazionaria), si dovrebbe lanciare la vostra int ad un doppio per fare il confronto:

bool isEqual = (double)iValue == dValue; 

Se qualcosa del genere 1,1 sarebbe considerato uguale a 1, puoi lanciare il doppio in un int (se vuoi ignorare del tutto la componente frazionaria) o arrotondare il doppio se vuoi dire 1,9 uguale a 2.

+0

Attenzione però all'arrotondamento. Molte persone sembrano sorprese quando 2.5 round a 2. – Joey

+0

@Joey È piuttosto semplice scrivere il proprio codice di arrotondamento per avere il comportamento desiderato se i tre built-in non soddisfano le proprie esigenze. – Casey

3

È una pessima idea per confrontare numeri interi e numeri in virgola mobile per l'uguaglianza in qualsiasi lingua. Funziona per casi molto semplici, ma dopo aver fatto qualsiasi calcolo matematico, la probabilità che il programma faccia ciò che vuoi diminuisca drasticamente.

Ha a che fare con il modo in cui i numeri in virgola mobile sono memorizzati su un sistema digitale binario.

Se si è certi di voler utilizzare questo, creare un corso per creare il proprio numero con le frazioni. utilizzare un int per mantenere l'intero numero e un altro int per mantenere la frazione.

0

Oggigiorno, praticamente l'unica volta uno dovrebbe essere confrontando i valori dei tipi double eo integer o long di uguaglianza rigorosa è quando, per qualche motivo, uno è memorizzazione bloccato o passando quantità integrali come valori in virgola mobile e necessità successive per riconvertirli. Nella maggior parte dei casi, tale conversione può essere eseguita più facilmente, convertendo il tipo integrale in double e quindi confrontando il risultato di tale cast. Si noti che la conversione da long a double può essere imprecisa se il numero non rientra nell'intervallo ± 2 . Tuttavia, nei giorni precedenti la disponibilità di 642 bit long, double era un pratico tipo di archiviazione per quantità di interi che erano troppo grandi per un int 32 bit, ma abbastanza piccolo da essere gestito da double.

noti che la conversione di un long per double e poi facendo il confronto produrrà un risultato "uguale" se il valore nominale del double non corrisponde esattamente al valore long, ma rappresenta il più vicino possibile double a tale valore. Questo comportamento ha senso se si riconosce che i tipi a virgola mobile non rappresentano in realtà un singolo valore preciso, ma piuttosto un intervallo di valori.

2
double val1 = 0; 
double val2 = 0.0; 
if((val1 - Double.Epsilon) < 0) 
{ 
    // Put your code here 
} 

     OR 

if((val2 - Double.Epsilon) < 0) 
{ 
    // Put your code here 
} 

dove Double.Epsilon è il valore più basso possibile per Double.