Existe uma maneira de obter os "números significativos" de um decimal?

Atualizar

OK, depois de alguma investigação, e em grande parte graças às respostas úteis fornecidas por Jon e Hans, foi isso que consegui reunir. Até agora, acho que parece funcionar bem. Eu não apostaria minha vida em sua total correção, é claro.

public static int GetSignificantDigitCount(this decimal value)
{
    /* So, the decimal type is basically represented as a fraction of two
     * integers: a numerator that can be anything, and a denominator that is 
     * some power of 10.
     * 
     * For example, the following numbers are represented by
     * the corresponding fractions:
     * 
     * VALUE    NUMERATOR   DENOMINATOR
     * 1        1           1
     * 1.0      10          10
     * 1.012    1012        1000
     * 0.04     4           100
     * 12.01    1201        100
     * 
     * So basically, if the magnitude is greater than or equal to one,
     * the number of digits is the number of digits in the numerator.
     * If it's less than one, the number of digits is the number of digits
     * in the denominator.
     */

    int[] bits = decimal.GetBits(value);

    if (value >= 1M || value <= -1M)
    {
        int highPart = bits[2];
        int middlePart = bits[1];
        int lowPart = bits[0];

        decimal num = new decimal(lowPart, middlePart, highPart, false, 0);

        int exponent = (int)Math.Ceiling(Math.Log10((double)num));

        return exponent;
    }
    else
    {
        int scalePart = bits[3];

        // Accoring to MSDN, the exponent is represented by
        // bits 16-23 (the 2nd word):
        // http://msdn.microsoft.com/en-us/library/system.decimal.getbits.aspx
        int exponent = (scalePart & 0x00FF0000) >> 16;

        return exponent + 1;
    }
}

Eu não testei tudo isso completamente. Aqui estão algumas entradas / saídas de amostra, no entanto:

Value          Precision
0              1 digit(s).
0.000          4 digit(s).
1.23           3 digit(s).
12.324         5 digit(s).
1.2300         5 digit(s).
-5             1 digit(s).
-5.01          3 digit(s).
-0.012         4 digit(s).
-0.100         4 digit(s).
0.0            2 digit(s).
10443.31       7 digit(s).
-130.340       6 digit(s).
-80.8000       6 digit(s).

Usando esse código, imagino que atingiria meu objetivo fazendo algo assim:

public static decimal DivideUsingLesserPrecision(decimal x, decimal y)
{
    int xDigitCount = x.GetSignificantDigitCount();
    int yDigitCount = y.GetSignificantDigitCount();

    int lesserPrecision = System.Math.Min(xDigitCount, yDigitCount);

    return System.Math.Round(x / y, lesserPrecision);
}

Ainda não terminei de trabalhar nisso. Quem quiser compartilhar pensamentos: isso seria muito apreciado!

Pergunta original

Suponha que eu escrevi este código:

decimal a = 1.23M;
decimal b = 1.23000M;

Console.WriteLine(a);
Console.WriteLine(b);

O exemplo acima será exibido:

1.23
1.23000

Acho que isso também funciona se eu usardecimal.Parse("1.23") paraa edecimal.Parse("1.23000") parab (o que significa que esta pergunta se aplica aos casos em que o programa recebe entrada do usuário).

Tão claramentedecimal O valor está de alguma forma "ciente" do que chamarei deprecisão. No entanto, não vejo membros nodecimal tipo que fornece qualquer maneira de acessar isso, além deToString em si.

Suponha que eu quisesse multiplicar doisdecimal valores e apara o resultado com a precisão do argumento menos preciso. Em outras palavras:

decimal a = 123.4M;
decimal b = 5.6789M;

decimal x = a / b;

Console.WriteLine(x);

As saídas acima:

21.729560302171195125816619416

O que estou perguntando é: como eu poderia escrever um método que retornaria21.73 em vez disso (desde123.4M tem quatro números significativos)?

Para ser claro: eu sei que poderia ligarToString nos dois argumentos, conte os números significativos em cada sequência e use esse número para arredondar o resultado do cálculo. eu estou procurando umadiferente maneira, se possível.

(EUAlém disso perceba que na maioria dos cenários em que você está lidando com números significativos, provavelmente não precisa usar odecimal tipo. Mas estou perguntando porque, como mencionei no começo, odecimal tipoaparece incluir informações sobre precisão, enquantodouble até onde eu sei.)

questionAnswers(3)

yourAnswerToTheQuestion