round L'arrotondamento decimale C#è incoerente?




funzione round (4)

La parte "singola cifra non nulla in d alla destra della posizione decimale dei decimali e il suo valore è 5" spiega il risultato. Solo quando la parte da arrotondare è esattamente 0,5, la regola dell'arrotondamento entra in gioco.

Ho combattuto la precisione decimale in C # derivante da un decimale SQL (38,30) e ho finalmente raggiunto una stranezza di arrotondamento. So che probabilmente sto trascurando l'ovvio qui, ma ho bisogno di un po 'di intuizione.

Il problema che sto avendo è che C # non produce quello che considererei un risultato coerente.

decimal a = 0.387518769125m;
decimal b = 0.3875187691250002636113061835m;

Console.WriteLine(Math.Round(a, 11));
Console.WriteLine(Math.Round(b, 11));
Console.WriteLine(Math.Round(a, 11) == Math.Round(b, 11));

I rendimenti

0.38751876912
0.38751876913
False

Uhh, 0,38751876913? Veramente? Cosa mi manca qui?

Da MSDN :

Se la cifra nella posizione dei decimali è dispari, viene cambiata in una cifra pari. Altrimenti, rimane invariato.

Perché vedo risultati incoerenti? La precisione aggiuntiva non cambia la "cifra nella posizione dei decimali" ...


Spostiamo entrambi i numeri su 11 cifre a sinistra:

38751876912,5
38751876912,50002636113061835

Usando l'arrotondamento del banchiere, arrotondiamo il primo verso il basso. Sotto ogni sistema di arrotondamento del punto medio arrotondiamo il secondo numero (perché non si trova nel punto centrale) .

.Net sta facendo esattamente quello che ci aspetteremmo.


Da MSDN:

Se c'è una singola cifra diversa da zero in d alla destra della posizione decimale dei decimals e il suo valore è 5 , la cifra nella posizione dei decimali viene arrotondata se è dispari, o lasciata invariata se è pari . Se d ha meno cifre frazionarie rispetto ai decimals , d viene restituito invariato.

Nel tuo primo caso

decimal a = 0.387518769125m;
Console.WriteLine(Math.Round(a, 11));

c'è una sola cifra a destra dell'11 ° posto e quel numero è 5 . Pertanto, poiché la posizione 11 è pari, rimane invariata . Quindi, ottieni

0.38751876912

Nel tuo secondo caso

decimal b = 0.3875187691250002636113061835m;
Console.WriteLine(Math.Round(b, 11));

non c'è una sola cifra a destra dell'11 ° posto. Pertanto, questo è l'arrotondamento verso l'alto della scuola elementare; arrotondi se la cifra successiva è maggiore di 4, altrimenti arrotondi. Dal momento che la cifra a destra dell'11 ° posto è più di 4 (è un 5), ci arrotoliamo per vedere

0.38751876913

Perché vedo risultati incoerenti?

Tu non sei. I risultati sono completamente coerenti con la documentazione.


Da MSDN - Metodo Math.Round (Decimal, Int32) :

Se c'è una singola cifra diversa da zero in d alla destra della posizione decimale dei decimali e il suo valore è 5, la cifra nella posizione dei decimali viene arrotondata se è dispari, o lasciata invariata se è pari. Se d ha meno cifre frazionarie rispetto ai decimali, d viene restituito invariato.

Il comportamento di questo metodo segue lo standard IEEE 754, sezione 4. Questo tipo di arrotondamento viene talvolta chiamato arrotondamento al più vicino o arrotondamento del banchiere. Riduce al minimo gli errori di arrotondamento che risultano dall'arrotondamento costante di un valore di punto medio in un'unica direzione.

Notare l'uso di una singola cifra diversa da zero . Questo corrisponde ai tuoi primi esempi, ma non al secondo.

E:

Per controllare il tipo di arrotondamento utilizzato dal metodo Round (Decimal, Int32), chiamare il sovraccarico Decimal.Round (Decimal, Int32, MidpointRounding).







rounding