round redondear quitar ejemplos decimals decimales c# .net math rounding string-formatting

c# - redondear - ¿Por qué.Net utiliza un algoritmo de redondeo en String.Format que es inconsistente con el algoritmo Math.Round() predeterminado?



round c# decimal (4)

Como nota histórica, la implementación original de Visual Basic de Format $ también fue inconsistente con round-to-even, también conocido como Rounding de Banker. El código original de Format $ fue escrito por Tim Paterson. Tal vez recuerdes que Tim fue el autor de un pequeño programa llamado QDOS (más tarde conocido como MS-DOS) que fue un buen vendedor durante un tiempo allí.

Quizás este sea otro caso de 25 años de compatibilidad con versiones anteriores.

He notado la siguiente inconsistencia en C # / .NET. Me preguntaba por qué es así.

Console.WriteLine("{0,-4:#.0} | {1,-4:#.0}", 1.04, Math.Round(1.04, 1)); Console.WriteLine("{0,-4:#.0} | {1,-4:#.0}", 1.05, Math.Round(1.05, 1)); Console.WriteLine("{0,-4:#.0} | {1,-4:#.0}", 1.06, Math.Round(1.06, 1)); Console.WriteLine("{0,-4:#.0} | {1,-4:#.0}", 1.14, Math.Round(1.14, 1)); Console.WriteLine("{0,-4:#.0} | {1,-4:#.0}", 1.15, Math.Round(1.15, 1)); Console.WriteLine("{0,-4:#.0} | {1,-4:#.0}", 1.16, Math.Round(1.16, 1)); Console.WriteLine(); Console.WriteLine("{0,-4:#.0} | {1,-4:#.0}", 1.04, Math.Round(1.04, 1, MidpointRounding.AwayFromZero)); Console.WriteLine("{0,-4:#.0} | {1,-4:#.0}", 1.05, Math.Round(1.05, 1, MidpointRounding.AwayFromZero)); Console.WriteLine("{0,-4:#.0} | {1,-4:#.0}", 1.06, Math.Round(1.06, 1, MidpointRounding.AwayFromZero)); Console.WriteLine("{0,-4:#.0} | {1,-4:#.0}", 1.14, Math.Round(1.14, 1, MidpointRounding.AwayFromZero)); Console.WriteLine("{0,-4:#.0} | {1,-4:#.0}", 1.15, Math.Round(1.15, 1, MidpointRounding.AwayFromZero)); Console.WriteLine("{0,-4:#.0} | {1,-4:#.0}", 1.16, Math.Round(1.16, 1, MidpointRounding.AwayFromZero));

Salida:

1.0 | 1.0 1.1 | 1.0 1.1 | 1.1 1.1 | 1.1 1.2 | 1.2 1.2 | 1.2 1.0 | 1.0 1.1 | 1.1 1.1 | 1.1 1.1 | 1.1 1.2 | 1.2 1.2 | 1.2

Parece que el comportamiento de formato de cadena predeterminado es redondear utilizando MidpointRounding.AwayFromZero en lugar de Math.Round (), el valor predeterminado de MidpointRounding.ToEven.


Parece que este problema es peor que una inconsistencia "simple":

double dd = 0.034999999999999996; Math.Round(dd, 2); // 0.03 Math.Round(dd, 2, MidpointRounding.AwayFromZero); // 0.03 Math.Round(dd, 2, MidpointRounding.ToEven); // 0.03 string.Format("{0:N2}", dd); // "0.04"

Esto es absolutamente plátanos. Quién sabe de dónde diablos obtiene "0.04" de.


Por favor, eche un vistazo aquí: Posible error: Matemáticas. La ronda devuelve resultados inconsistentes

WriteLine () simplemente llama a Object.ToString (), que a su vez resulta en una llamada a Number.FormatDouble (this, null , NumberFormatInfo.CurrentInfo). Como puede ver, el parámetro para la cadena de formato es nulo. Si desea obtener el objeto real de ToString (), debe usar System.Diagnostics.Debug.WriteLine (n.ToString ("R")).

"Cuando se formatea un valor simple o doble con este especificador, primero se prueba con el formato general, con 15 dígitos de precisión para un doble y 7 dígitos de precisión para un solo. Si el valor se analiza con éxito al mismo valor numérico valor, se formatea utilizando el especificador de formato general. Si el valor no se analiza con éxito al mismo valor numérico, se formatea con 17 dígitos de precisión para un doble y 9 dígitos de precisión para un solo ". Cadenas de formato numérico estándar


WriteLine(string, params object[]) llama a string.Format y pasa la información de string.Format actual, por lo que utilizará su NumberFormatInfo localizado para determinar cómo escribir el número. Math.Round no tiene en cuenta la cultura, ya que estás especificando exactamente cómo quieres que se redondee.

Hm, después de hurgar en Reflector, tal vez no :)