Question

Mise à jour

OK, après une enquête, et merci grande partie des réponses utiles fournies par Jon et Hans, ce que j'ai pu mettre ensemble. Jusqu'à présent, je pense qu'il semble bien fonctionner. Je ne parierais pas ma vie sur l'exactitude totale, bien sûr.

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;
    }
}

Je l'ai pas testé tout ce fond. Voici quelques entrées / sorties d'échantillons, bien que:

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).

En utilisant ce code, j'imagine que j'accomplir mon but en faisant quelque chose comme ceci:

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);
}

Je n'ai pas vraiment fini de travailler à travers cela, cependant. Toute personne qui veut partager des idées: ce serait très apprécié


Question originale

Supposons que j'écrire ce code:

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

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

Le ci-dessus en sortie:

1.23
1.23000

Je trouve que cela fonctionne aussi si j'utilise decimal.Parse("1.23") pour a et decimal.Parse("1.23000") pour b (ce qui signifie que cette question s'applique aux cas où reçoit l'entrée d'utilisateur du programme).

Il apparaît donc clairement une valeur decimal est en quelque sorte « au courant » de ce que je vais appeler son précision . Cependant, je ne vois aucun membre sur le type de decimal qui fournissent une façon d'accéder à ce, en dehors de ToString lui-même.

Supposons que je voulais multiplier deux valeurs decimal et taillez le résultat à la précision de l'argument moins précis. En d'autres termes:

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

decimal x = a / b;

Console.WriteLine(x);

Les sorties ci-dessus:

21.729560302171195125816619416

Ce que je vous pose la question est: comment pourrais-je écrire une méthode qui retournerait 21.73 à la place (depuis 123.4M a quatre chiffres significatifs)

Pour être clair: je me rends compte que je pourrais appeler ToString sur les deux arguments, compter les chiffres significatifs dans chaque chaîne, et utiliser ce numéro pour arrondir le résultat du calcul. Je cherche un différent façon, si possible.

(I aussi se rendre compte que dans la plupart des scénarios où vous avez affaire à des chiffres significatifs, vous n'avez pas besoin probablement d'être en utilisant le type de decimal. Mais je demande parce que, comme je l'ai mentionné au début, le type de decimal apparaît pour inclure des informations sur la précision, alors que double n'a pas, pour autant que je sais.)

Était-ce utile?

La solution

Vous pouvez utiliser Decimal.GetBits pour obtenir le données brutes, et le travail hors de cela.

Malheureusement, je n'ai pas le temps de l'exemple de code d'écriture au moment - et vous voudrez probablement utiliser

Autres conseils

La solution ci-dessus tombe du lit rapidement avec des valeurs telles que 1200 où le nombre de chiffres significatifs est 2, mais la fonction retourne 4. Peut-être il y a une manière cohérente pour faire face à une telle situation ex.chèque pour vous assurer que la valeur de rendement ne comprennent des zéros de fin dans la partie entière du nombre sans partie décimale.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top