Quindi mi sto tuffando in questo problema ... Ho un'applicazione web molto utilizzata che, per la prima volta in 2 anni, non ha eseguito un controllo di uguaglianza su due doppi utilizzando la funzione di uguaglianza che un collega ha detto stava anche usando da anni.Problemi con il controllo dell'uguaglianza di due doppi in .NET - cosa c'è di sbagliato in questo metodo?
L'obiettivo della funzione che sto per incollare qui è di confrontare due valori doppi a 4 cifre di precisione e restituire i risultati del confronto. Per motivi di illustrazione, i miei valori sono:
Dim double1 As Double = 0.14625000000000002 ' The result of a calculation
Dim double2 As Double = 0.14625 ' A value that was looked up in a DB
Se li passo in questa funzione:
Public Shared Function AreEqual(ByVal double1 As Double, ByVal double2 As Double) As Boolean
Return (CType(double1 * 10000, Long) = CType(double2 * 10000, Long))
End Function
il paragone non regge. Dopo la moltiplicazione e cast a Long, il paragone finisce per essere:
Return 1463 = 1462
Sono una specie di rispondere alla mia domanda proprio qui, ma posso vedere che double1
è dentro la precisione di un doppio (17 cifre) e il cast funziona correttamente.
La mia prima vera domanda è: se cambio la riga sopra alla seguente, perché funziona correttamente (restituisce True
)?
Return (CType(CType(double1, Decimal) * 10000, Long) = _
CType(CType(double2, Decimal) * 10000, Long))
Does not Decimal
avere una precisione ancora maggiore, in tal modo il cast a Long dovrebbe essere ancora 1463
, e il confronto tornare False
? Penso che sto avendo una scoreggia cerebrale su questa roba ...
In secondo luogo, se dovessi cambiare questa funzione per rendere il confronto che sto cercando più preciso o meno soggetto a errori, consiglieresti di cambiarlo in qualcosa di molto più semplice? Per esempio:
Return (Math.Abs(double1 - double2) < 0.0001)
sarei pazzo a provare qualcosa di simile:
Return (double1.ToString("N5").Equals(double2.ToString("N5")))
(non avrei mai fare quanto sopra, sono solo curioso di sapere le vostre reazioni Sarebbe terribilmente inefficiente nel mio. applicazione.)
In ogni caso, se qualcuno potesse far luce sulla differenza che sto vedendo tra il casting Double
se Decimal
s a Long
, sarebbe fantastico.
Grazie!
"... il cast dal doppio al decimale sta perdendo precisione ..." Questo mi fa male al cervello. Perché la precisione si perde? È perché un decimale è una base diversa rispetto al doppio; cioè perché i numeri sono memorizzati in modo diverso? –
Non importa. Sto scrivendo senza pensare. Intendevo che il cast si stava restringendo (cioè perdendo informazioni), il che è vero, ma non riesco a capire perché. In base alla documentazione Decimal, la trasmissione da Double a Decimal non perde nulla, ma il debugger mostra la porzione minuscola che scompare: ad esempio Dim test As New Decimal (0,14625000000000002) restituisce un test contenente 0,14625. Tuttavia, Dim test As Decimal = 0.14625000000000002D funziona. Andrò a leggere l'articolo collegato sull'aritmetica in virgola mobile e smetterò di rispondere a questo punto ... –
E un altro po 'di ricerca attraverso la documentazione mostra: "Questo costruttore arrotonda il valore a 15 cifre significative usando l'arrotondamento al più vicino. il numero ha più di 15 cifre e le cifre meno significative sono zero." –