小数点以下の桁数を見つけるための最良の解決策の 1 つは、burning_LEGION の投稿に示されています。
ここでは、STSdb フォーラムの記事Number of digits after decimal point の一部を使用しています。
MSDN では、次の説明を読むことができます。
「10 進数は、符号、値の各桁の範囲が 0 から 9 の数値、および整数と小数を区切る浮動小数点の位置を示すスケーリング係数で構成される浮動小数点値です。数値の一部です。」
また:
「Decimal 値のバイナリ表現は、1 ビットの符号、96 ビットの整数、および 96 ビットの整数を除算し、小数部分を指定するために使用されるスケーリング係数で構成されます。スケーリング係数は暗黙のうちに 10 を 0 から 28 までの指数で累乗したものです。」
内部レベルでは、10 進数値は 4 つの整数値で表されます。

内部表現を取得するための公開されている GetBits 関数があります。関数は int[] 配列を返します。
[__DynamicallyInvokable]
public static int[] GetBits(decimal d)
{
return new int[] { d.lo, d.mid, d.hi, d.flags };
}
返された配列の 4 番目の要素には、倍率と符号が含まれます。また、MSDN によると、倍率は暗黙的に 10 を 0 から 28 までの指数で累乗したものです。これはまさに私たちが必要としているものです。
したがって、上記のすべての調査に基づいて、メソッドを構築できます。
private const int SIGN_MASK = ~Int32.MinValue;
public static int GetDigits4(decimal value)
{
return (Decimal.GetBits(value)[3] & SIGN_MASK) >> 16;
}
ここでは、符号を無視するために SIGN_MASK が使用されています。論理演算の後、結果を 16 ビットで右にシフトして、実際のスケール ファクターを受け取ります。最後に、この値は小数点以下の桁数を示します。
ここでMSDNは、スケーリング係数も10進数の末尾のゼロを保持すると述べていることに注意してください。末尾のゼロは、算術演算または比較演算の 10 進数の値には影響しません。ただし、適切な書式文字列が適用されている場合、ToString メソッドによって末尾のゼロが明らかになることがあります。
この解決策が最善の解決策のように見えますが、待ってください。他にもあります。C# でプライベート メソッドにアクセスすることにより、式を使用して flags フィールドへの直接アクセスを構築し、int 配列の構築を回避できます。
public delegate int GetDigitsDelegate(ref Decimal value);
public class DecimalHelper
{
public static readonly DecimalHelper Instance = new DecimalHelper();
public readonly GetDigitsDelegate GetDigits;
public readonly Expression<GetDigitsDelegate> GetDigitsLambda;
public DecimalHelper()
{
GetDigitsLambda = CreateGetDigitsMethod();
GetDigits = GetDigitsLambda.Compile();
}
private Expression<GetDigitsDelegate> CreateGetDigitsMethod()
{
var value = Expression.Parameter(typeof(Decimal).MakeByRefType(), "value");
var digits = Expression.RightShift(
Expression.And(Expression.Field(value, "flags"), Expression.Constant(~Int32.MinValue, typeof(int))),
Expression.Constant(16, typeof(int)));
//return (value.flags & ~Int32.MinValue) >> 16
return Expression.Lambda<GetDigitsDelegate>(digits, value);
}
}
このコンパイルされたコードは、GetDigits フィールドに割り当てられます。この関数は 10 進数値を ref として受け取るため、実際のコピーは実行されず、値への参照のみであることに注意してください。DecimalHelper から GetDigits 関数を使用するのは簡単です。
decimal value = 3.14159m;
int digits = DecimalHelper.Instance.GetDigits(ref value);
これは、10 進数値の小数点以下の桁数を取得するための最速の方法です。