11

ユーザー入力 (テキストボックス) の小数精度を決定する必要があるという興味深い問題があります。基本的に、入力された小数点以下の桁数を知り、精度の数値を返す必要があります。これは、例で最もよく説明されています。

4500 を入力すると結果 1
が返されます 4500.1 を入力すると結果が 0.1
になります 4500.00 を入力すると結果が 0.01
になります 4500.450 を入力すると結果が 0.001 になります

文字列を操作して、小数点記号を見つけてから結果を計算することを考えています。これに対するより簡単な解決策があるかどうか疑問に思っています。

4

7 に答える 7

19

あなたが提案したことをするべきだと思います-小数点の位置を使用してください。明らかな欠点は、国際化について自分で考えなければならないことです。

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;
}
于 2010-07-19T14:25:42.403 に答える
11

これに対するより簡単な解決策があるかどうか疑問に思っています。

いいえ。

使用文字列:

string[] res = inputstring.Split('.');
int precision = res[1].Length;
于 2010-07-19T14:24:28.853 に答える
8

最後の例は、末尾のゼロが重要であることを示しているため、数値解を除外して文字列操作を行います。

于 2010-07-19T14:20:26.983 に答える
3

いいえ、簡単な解決策はありません。文字列を調べる必要があります。"4500""4500.00"を数値に変換すると、どちらも値になる4500ため、小数点の後ろに値以外の桁がいくつあるかわかりません。

于 2010-07-19T14:21:59.760 に答える
2

興味深いことに、Decimalはユーザーが入力した精度を維持しようとします。例えば、

Console.WriteLine(5.0m);
Console.WriteLine(5.00m);
Console.WriteLine(Decimal.Parse("5.0"));
Console.WriteLine(Decimal.Parse("5.00"));

次の出力があります。

5.0
5.00
5.0
5.00

入力の精度を追跡する動機が純粋に入力と出力の理由である場合は、これで問題を解決するのに十分な場合があります。

于 2010-07-19T14:29:39.443 に答える
1

文字列の操作は簡単です。

「.」がない場合 文字列では、1 を返します。

それ以外の場合は、"0." を返し、その後に n-1 "0" が続き、その後に 1 つの "1" が続きます。ここで、n は小数点以下の文字列の長さです。

于 2010-07-19T14:24:12.177 に答える
1

文字列を使用した可能な解決策は次のとおりです。

static double GetPrecision(string s)
{ 
    string[] splitNumber = s.Split('.');
    if (splitNumber.Length > 1)
    {
        return 1 / Math.Pow(10, splitNumber[1].Length);
    }
    else
    {
        return 1;
    }
}

ここで質問があります。これをさらに掘り下げたい場合は、System.Decimal の精度とスケールを計算してください。

于 2010-07-19T14:34:54.923 に答える