errore di arrotondamento C # del banchiere
-
04-10-2019 - |
Domanda
double a = 18.565
return Math.Round(a,2)
.. ritorna 18.57.
Per ogni altro numero ho provato banchiere di arrotondamento ha funzionato come previsto, ad esempio Math.round (2.565,2) ha restituito 2,56.
Ogni indizio perché e quando ciò accade? E 'error o mi sto perdendo qualcosa circa arrotondamento?
Grazie ..
Soluzione
Come detto Matthew, 18,565 non possono essere rappresentati con precisione. Il valore effettivo utilizzato è 18.565000000000001278976924368180334568023681640625 (trovato utilizzando DoubleConverter ), che è chiaramente oltre la metà -modo. Ora ho la sensazione che furtivamente a volte Math.Round
si considerano un valore che è effettivamente oltre il punto a metà strada, ma che è il più vicino al punto a metà strada come può essere accuratamente rappresentato, come esattamente a quel punto. Tuttavia, non ho visto alcuna documentazione che descrive le situazioni in cui che viene applicato, e chiaramente non sta accadendo in questo caso. Non vorrei fare affidamento su di esso.
Anche il valore arrotondato non è esattamente 18.57, naturalmente. In realtà è 18,57000000000000028421709430404007434844970703125.
In sostanza, se davvero, davvero a cuore che rappresenta i valori decimali con precisione, si dovrebbe utilizzare decimal
. Questo non è solo in termini di Math.Round
-. Va a tutti gli aspetti della gestione dei valori in virgola mobile
che non dare il giusto valore per Math.Round
, naturalmente:
decimal m = 18.565m;
Console.WriteLine(Math.Round(m, 2)); // Prints 18.56
Altri suggerimenti
18,565 non può essere esattamente rappresentato come un doppio. Così, la rappresentazione binaria è leggermente superiore, in modo che arrotonda. Se si utilizza decimali:
decimal a = 18.565m;
return Math.Round(a,2)
può essere esattamente rappresentato, e non avrà questo problema.
La mia ipotesi è che i mezzi di rappresentazione FP non è in realtà un trailing 5; i pericoli di FP!
Questo funziona bene, però:
decimal a = 18.565M; // <===== decimal
var s = Math.Round(a, 2);
Double è un valore in virgola mobile, quindi forse se si scrive come 18,565, in realtà è qualcosa in memoria come 18,56500000000000000000000000000000001, e quindi è più che il punto medio.