Ajuste de precisión decimal, .net

Estas líneas en C #

decimal a = 2m; decimal b = 2.0m; decimal c = 2.00000000m; decimal d = 2.000000000000000000000000000m; Console.WriteLine(a); Console.WriteLine(b); Console.WriteLine(c); Console.WriteLine(d); 

Genera esta salida:

 2 2.0 2.00000000 2.000000000000000000000000000 

Entonces puedo ver que crear una variable decimal a partir de un literal me permite controlar la precisión.

  • ¿Puedo ajustar la precisión de las variables decimales sin usar literales?
  • ¿Cómo puedo crear b desde a? ¿Cómo puedo crear b desde c?

La preservación de ceros finales como este se introdujo en .NET 1.1 para una conformidad más estricta con la especificación ECMA CLI.

Hay algo de información sobre esto en MSDN, por ejemplo aquí .

Puede ajustar la precisión de la siguiente manera:

  • Math.Round (o techo, piso, etc.) para disminuir la precisión (b de c)

  • Multiplique por 1.000 … (con el número de decimales que desee) para boost la precisión, por ejemplo, multiplique por 1.0M para obtener b de a.

Solo está viendo representaciones diferentes de los mismos datos exactos. La precisión de un decimal se escalará para que sea tan grande como debe ser (dentro de lo razonable).

De System.Decimal :

Un número decimal es un valor de coma flotante que consiste en un signo, un valor numérico donde cada dígito en el rango de valores va de 0 a 9 y un factor de escala que indica la posición de un punto decimal flotante que separa las partes integrales y fraccionarias del valor numérico.

La representación binaria de un valor decimal consiste en un signo de 1 bit, un número entero de 96 bits y un factor de escala utilizado para dividir el entero de 96 bits y especificar qué parte de él es una fracción decimal. El factor de escala es implícitamente el número 10, elevado a un exponente que va de 0 a 28. Por lo tanto, la representación binaria de un valor decimal es de la forma, ((-2 96 a 2 96 ) / 10 (0 a 28) ) , donde -2 96 -1 es igual a MinValue, y 2 96 -1 es igual a MaxValue.

El factor de escala también conserva los ceros finales en un número decimal. Los ceros finales no afectan el valor de un número decimal en operaciones aritméticas u operaciones de comparación. Sin embargo, el método ToString puede revelar los ceros finales si se aplica una cadena de formato adecuada.

¿Qué pasa con Math.Round (decimal d, int decimales) ?

Descubrí que podía “manipular” la escala multiplicando o dividiendo por un 1 de lujo.

 decimal a = 2m; decimal c = 2.00000000m; decimal PreciseOne = 1.000000000000000000000000000000m; //add maximum trailing zeros to a decimal x = a * PreciseOne; //remove all trailing zeros from c decimal y = c / PreciseOne; 

Puedo fabricar un 1 suficientemente preciso para cambiar los factores de escala por tamaños conocidos.

 decimal scaleFactorBase = 1.0m; decimal scaleFactor = 1m; int scaleFactorSize = 3; for (int i = 0; i < scaleFactorSize; i++) { scaleFactor *= scaleFactorBase; } decimal z = a * scaleFactor; 

Es tentador confundir decimal en SQL Server con decimal en .NET; son bastante diferentes.

Un decimal SQL Server es un número de punto fijo cuya precisión y escala son fijas cuando se define la columna o variable.

Un .NET decimal es un número de coma flotante como float y double (la diferencia es que ese decimal preserva con precisión los dígitos decimales mientras que float y double preservan con precisión los dígitos binarios). Intentar controlar la precisión de un decimal .NET no tiene sentido, ya que todos los cálculos producirán los mismos resultados independientemente de la presencia o ausencia de ceros de relleno.

La pregunta es: ¿realmente necesita la precisión almacenada en el decimal, en lugar de solo mostrar el decimal con la precisión requerida? La mayoría de las aplicaciones saben internamente qué tan precisas quieren ser y cómo se muestran con ese nivel de precisión. Por ejemplo, incluso si un usuario ingresa una factura por 100 en un paquete de cuentas, aún se imprime como 100.00 usando algo como val.ToString (“n2”).

¿Cómo puedo crear b desde a? ¿Cómo puedo crear b desde c?

c to b es posible.

 Console.WriteLine(Math.Round(2.00000000m, 1)) 

produce 2.0

de a b es complicado ya que el concepto de introducir precisión es un poco extraño para las matemáticas.

Creo que un truco horrible podría ser un viaje redondo.

 decimal b = Decimal.Parse(a.ToString("#.0")); Console.WriteLine(b); 

produce 2.0

Esto eliminará todos los ceros finales del decimal y luego solo puede usar ToString() .

 public static class DecimalExtensions { public static Decimal Normalize(this Decimal value) { return value / 1.000000000000000000000000000000000m; } } 

O, como alternativa, si quiere un número exacto de ceros finales, digamos 5, primero Normalize () y luego multiplique por 1.00000m.