あなたが提案したことをするべきだと思います-小数点の位置を使用してください。明らかな欠点は、国際化について自分で考えなければならないことです。
var decimalSeparator = NumberFormatInfo.CurrentInfo.CurrencyDecimalSeparator;
var position = input.IndexOf(decimalSeparator);
var precision = (position == -1) ? 0 : input.Length - position - 1;
// This may be quite unprecise.
var result = Math.Pow(0.1, precision);
試すことができる別のことがあります-Decimal
型は内部精度値を格納します。Decimal.TryParse()
したがって、戻り値を使用して調べることができます。解析アルゴリズムが入力の精度を維持している可能性があります。
最後に、浮動小数点数を使用して何かを試さないことをお勧めします。入力を解析するだけで、末尾のゼロに関する情報が削除されます。したがって、それらを保持するか、同様のトリックを行うために、ゼロ以外の人工的な数字を追加する必要があります。精度の問題が発生する可能性があります。最後に、浮動小数点数に基づいて精度を見つけることも簡単ではありません。小数部分がなくなるまで、醜い数学またはループが反復ごとに 10 倍になることがわかります。そして、ループには新しい精度の問題が伴います...
アップデート
小数への解析は機能します。詳細Decimal.GetBits()
については、を参照してください。
var input = "123.4560";
var number = Decimal.Parse(input);
// Will be 4.
var precision = (Decimal.GetBits(number)[3] >> 16) & 0x000000FF;
ここから使用するMath.Pow(0.1, precision)
のは簡単です。
更新 2
decimal.GetBits() を使用すると、int[]
配列が割り当てられます。割り当てを回避したい場合は、明示的なレイアウト構造体を使用して 10 進数値からスケールを直接取得する次のヘルパー メソッドを使用できます。
static int GetScale(decimal d)
{
return new DecimalScale(d).Scale;
}
[StructLayout(LayoutKind.Explicit)]
struct DecimalScale
{
public DecimalScale(decimal value)
{
this = default;
this.d = value;
}
[FieldOffset(0)]
decimal d;
[FieldOffset(0)]
int flags;
public int Scale => (flags >> 16) & 0xff;
}