Dot-Net

計算 System.Decimal 精度和比例

  • April 18, 2009

假設我們有一個 System.Decimal 數字。

舉個例子,我們來看一個 ToString() 表示如下:

d.ToString() = "123.4500"

關於這個十進制可以說以下內容。出於我們的目的,比例定義為小數點右側的位數。有效比例類似,但忽略小數部分中出現的任何尾隨零。(換句話說,這些參數的定義類似於 SQL 小數加上一些附加參數,以說明 System.Decimal 小數部分尾隨零的概念。)

  • 精度:7
  • 規模:4
  • 有效精度:5
  • 有效規模:2

給定一個任意的 System.Decimal,我怎樣才能有效地計算所有這四個參數而不轉換為字元串並檢查字元串?該解決方案可能需要 Decimal.GetBits。

更多範例:

Examples Precision  Scale  EffectivePrecision  EffectiveScale
0        1 (?)      0      1 (?)               0
0.0      2 (?)      1      1 (?)               0
12.45    4          2      4                   2
12.4500  6          4      4                   2
770      3          0      3                   0

(?) 或者將這些精度解釋為零也可以。

是的,您需要使用Decimal.GetBits. 不幸的是,您必須使用 96 位整數,而 .NET 中沒有簡單的整數類型可以處理 96 位。另一方面,您可能會使用Decimal自己…

這是一些產生與您的範例相同的數字的程式碼。希望你覺得它有用 :)

using System;

public class Test
{
   static public void Main(string[] x)
   {
       ShowInfo(123.4500m);
       ShowInfo(0m);
       ShowInfo(0.0m);
       ShowInfo(12.45m);
       ShowInfo(12.4500m);
       ShowInfo(770m);
   }

   static void ShowInfo(decimal dec)
   {
       // We want the integer parts as uint
       // C# doesn't permit int[] to uint[] conversion,
       // but .NET does. This is somewhat evil...
       uint[] bits = (uint[])(object)decimal.GetBits(dec);


       decimal mantissa = 
           (bits[2] * 4294967296m * 4294967296m) +
           (bits[1] * 4294967296m) +
           bits[0];

       uint scale = (bits[3] >> 16) & 31;

       // Precision: number of times we can divide
       // by 10 before we get to 0        
       uint precision = 0;
       if (dec != 0m)
       {
           for (decimal tmp = mantissa; tmp >= 1; tmp /= 10)
           {
               precision++;
           }
       }
       else
       {
           // Handle zero differently. It's odd.
           precision = scale + 1;
       }

       uint trailingZeros = 0;
       for (decimal tmp = mantissa;
            tmp % 10m == 0 && trailingZeros < scale;
            tmp /= 10)
       {
           trailingZeros++;
       }

       Console.WriteLine("Example: {0}", dec);
       Console.WriteLine("Precision: {0}", precision);
       Console.WriteLine("Scale: {0}", scale);
       Console.WriteLine("EffectivePrecision: {0}",
                         precision - trailingZeros);
       Console.WriteLine("EffectiveScale: {0}", scale - trailingZeros);
       Console.WriteLine();
   }
}

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