Dot-Net

有沒有辦法獲得小數的“重要數字”?

  • February 2, 2017

更新

好的,經過一番調查,在很大程度上要感謝 Jon 和 Hans 提供的有用答案,這就是我能夠整理出來的。到目前為止,我認為它似乎運作良好。當然,我不會賭它的完全正確性。

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

我還沒有徹底測試它。不過,這裡有一些範例輸入/輸出:

價值精度
0 1 位數。
0.000 4 位數。
1.23 3 位數。
12.324 5 位數。
1.2300 5 位數。
-5 1 位數。
-5.01 3 位數。
-0.012 4 位數。
-0.100 4 位數。
0.0 2 位數。
10443.31 7 位數。
-130.340 6 位數。
-80.8000 6 位數。

使用此程式碼,我想我會通過執行以下操作來實現我的目標:

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

不過,我還沒有真正完成這個工作。任何想分享想法的人:將不勝感激!


原始問題

假設我寫了這段程式碼:

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

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

以上將輸出:

1.23
1.23000

我發現如果我使用decimal.Parse("1.23")foradecimal.Parse("1.23000")for這也有效b(這意味著這個問題適用於程序接收使用者輸入的情況)。

很明顯,一個decimal值以某種方式“意識到”了我所說的精度decimal但是,除了ToString自身之外,我沒有看到該類型的成員提供任何訪問方式。

假設我想將兩個decimal值相乘並將結果修剪到不太精確的參數的精度。換一種說法:

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

decimal x = a / b;

Console.WriteLine(x);

上述輸出:

21.729560302171195125816619416

我要問的是:我怎麼能寫一個返回的方法21.73(因為123.4M有四個有效數字)?

明確一點:我意識到我可以呼叫ToString這兩個參數,計算每個字元串中的有效數字,並使用這個數字對計算結果進行四捨五入。如果可能的話,我正在尋找一種不同的方式。

(我意識到,在您處理有效數字的大多數情況下,您可能不需要使用該decimal類型。但我問是因為,正如我在開頭提到的那樣,該decimal類型似乎包含有關精度,而double據我所知沒有。)

您可以使用它Decimal.GetBits來獲取原始數據,並從中計算出來。

不幸的是,我目前沒有時間編寫範常式式碼 -BigInteger如果您使用 .NET 4,您可能希望使用一些操作來進行操作 - 但希望這會讓您繼續前進。僅僅計算出精度然後呼叫Math.Round原始結果可能是一個好的開始。

是的,與浮點類型不同,System.Decimal 跟踪文字中的位數。這是 decimal.Parse() 的一個特性,無論是由您的程式碼自己執行還是由編譯器在解析程序中的文字時執行。您可以恢復此資訊,查看我在此執行緒中的答案中的程式碼。

在對值進行數學運算後恢復有效位數讓我覺得很遙遠。不知道運營商是否保留它們,請告訴我們您的發現。

引用自:https://stackoverflow.com/questions/3683718