Ajustando precisão decimal, .net

Essas linhas em 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); 

Gera esta saída:

 2 2.0 2.00000000 2.000000000000000000000000000 

Então eu posso ver que criar uma variável decimal a partir de um literal me permite controlar a precisão.

  • Posso ajustar a precisão das variables ​​decimais sem usar literais?
  • Como posso criar b de um? Como posso criar b de c?

A preservação de zeros à direita como este foi introduzida no .NET 1.1 para uma conformidade mais estrita com a especificação CLI do ECMA.

Há algumas informações sobre isso no MSDN, por exemplo, aqui .

Você pode ajustar a precisão da seguinte forma:

  • Math.Round (ou teto, chão, etc) para diminuir a precisão (b de c)

  • Multiplique por 1.000 … (com o número de casas decimais que você quer) para aumentar a precisão – por exemplo, multiplique por 1.0M para obter b de a.

Você está vendo apenas diferentes representações dos mesmos dados. A precisão de um decimal será dimensionada para ser tão grande quanto precisa ser (dentro da razão).

Do System.Decimal :

Um número decimal é um valor de ponto flutuante que consiste em um sinal, um valor numérico em que cada dígito no valor varia de 0 a 9 e um fator de escala que indica a posição de um ponto decimal flutuante que separa as partes integral e fracionária. do valor numérico.

A representação binária de um valor Decimal consiste em um sinal de 1 bit, um número inteiro de 96 bits e um fator de escala usado para dividir o inteiro de 96 bits e especificar qual parte dele é uma fração decimal. O fator de escala é implicitamente o número 10, aumentado para um expoente variando de 0 a 28. Portanto, a representação binária de um valor Decimal é da forma, ((-2 96 a 2 96 ) / 10 (0 a 28) ) , onde -2 96 -1 é igual a MinValue e 2 96 -1 é igual a MaxValue.

O fator de escala também preserva qualquer zeros à direita em um número Decimal. Zeros à direita não afetam o valor de um número Decimal em operações aritméticas ou de comparação. No entanto, zeros à direita podem ser revelados pelo método ToString se uma string de formato apropriada for aplicada.

E o Math.Round (decimal d, int decimais) ?

Descobri que eu poderia “adulterar” a escala multiplicando ou dividindo por uma fantasia 1.

 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; 

Eu posso fabricar um 1 suficientemente preciso para alterar os fatores de escala por tamanhos conhecidos.

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

É tentador confundir decimal no SQL Server com decimal no .NET; eles são bem diferentes.

Um decimal SQL Server é um número de ponto fixo cuja precisão e escala são fixadas quando a coluna ou variável é definida.

Um decimal .NET é um número de ponto float como float e double (a diferença é que o decimal preserva com precisão dígitos decimais, enquanto float e double preservam com precisão os dígitos binários). A tentativa de controlar a precisão de um decimal .NET é inútil, pois todos os cálculos produzirão os mesmos resultados, independentemente da presença ou ausência de zeros de preenchimento.

A questão é: você realmente precisa da precisão armazenada no decimal, em vez de apenas exibir o decimal com a precisão necessária. A maioria dos aplicativos sabe internamente como eles querem ser precisos e exibem esse nível de precisão. Por exemplo, mesmo que um usuário insira uma fatura de 100 em um pacote de contas, ele ainda será impresso como 100,00 usando algo como val.ToString (“n2”).

Como posso criar b de um? Como posso criar b de c?

c para b é possível.

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

produz 2.0

A para b é complicado como o conceito de introdução de precisão é um pouco estranho para a matemática.

Eu acho que um hack horrível poderia ser uma viagem de ida e volta.

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

produz 2.0

Isso removerá todos os zeros à direita do decimal e você poderá usar ToString() .

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

Ou, como alternativa, se você quiser um número exato de zeros à direita, diga 5, primeiro Normalize () e, em seguida, multiplique por 1,00000m.