17

私は単純なC#関数を持っています:

public static double Floor(double value, double step)
{
    return Math.Floor(value / step) * step;
}

これは、「ステップ」の倍数である「値」以下の大きい数を計算します。ただし、次のテストで見られるように、精度が不足しています。

[TestMethod()]
public void FloorTest()
{
    int decimals = 6;
    double value = 5F;
    double step = 2F;
    double expected = 4F;
    double actual = Class.Floor(value, step);
    Assert.AreEqual(expected, actual);
    value = -11.5F;
    step = 1.1F;
    expected = -12.1F;
    actual = Class.Floor(value, step);
    Assert.AreEqual(Math.Round(expected, decimals),Math.Round(actual, decimals));
    Assert.AreEqual(expected, actual);
}

1 番目と 2 番目のアサートは問題ありませんが、3 番目のアサートは失敗します。これは、結果が小数第 6 位までしか変わらないためです。何故ですか?これを修正する方法はありますか?

更新テストをデバッグすると、値が小数点以下 6 桁目ではなく 8 桁目まで等しいことがわかります。これは、おそらく Math.Round によって不正確さが生じるためです。

注:私のテスト コードでは、"D" (倍精度) を意味するところに "F" 接尾辞 (明示的な浮動小数点定数) を書きました。

4

9 に答える 9

11

私は実際には、float と double に対して == 演算子を実装していなかったらよかったのにと思います。double または float が他の値と等しいかどうかを尋ねることは、ほとんどの場合間違ったことです。

于 2009-07-03T11:37:37.530 に答える
7

コンピューター上の浮動小数点演算は精密科学ではありません:)。

事前定義された小数点以下の桁数に正確な精度が必要な場合は、doubleではなくDecimalを使用するか、マイナー間隔を受け入れます。

于 2009-02-19T20:24:19.143 に答える
7

精度が必要な場合は、System.Decimalを使用してください。速度が必要な場合は、System.Double(またはSystem.Float)を使用します。浮動小数点数は「無限精度」の数ではないため、同等性を主張するには許容誤差を含める必要があります。あなたの数が有効数字の妥当な数を持っている限り、これは大丈夫です。

  • 非常に大きい数と非常に小さい数で数学を実行する場合は、floatまたはdoubleを使用しないでください。
  • 無限の精度が必要な場合は、floatまたはdoubleを使用しないでください。
  • 非常に多くの値を集計する場合は、floatまたはdoubleを使用しないでください(エラーはそれ自体を悪化させます)。
  • 速度とサイズが必要な場合は、floatまたはdoubleを使用してください。

精度が数学演算の結果にどのように影響するかについての詳細な分析については、この回答(私も)を参照してください。

于 2009-02-19T21:00:03.907 に答える
6

すべてのF接尾辞を(つまり-12.1、の代わりに-12.1F)省略すると、さらに数桁の同等性が得られます。定数(特に期待値)は、。のために浮動小数点になりFます。わざとそうしているのなら説明してください。

しかし、残りの部分については、double値またはfloat値を比較して等しいかどうかについて他の回答に同意しますが、それは信頼できません。

于 2009-02-19T20:31:22.217 に答える
5

http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems

たとえば、0.1 と 0.01 (バイナリ) の非表現可能性は、0.1 を 2 乗しようとした結果が 0.01 でもそれに最も近い表現可能数でもないことを意味します。

数値システムのマシンの解釈 (バイナリ) が必要な場合にのみ、浮動小数点を使用してください。10 セントを表すことはできません。

于 2009-02-19T20:31:52.777 に答える
3

この質問に対する答えを確認してください:浮動小数点値が0に等しいかどうかを確認するのは安全ですか?

本当に、「許容範囲内...」をチェックするだけです。

于 2009-02-19T20:21:48.273 に答える
1

floatとdoubleは、すべての数値を正確に格納できるわけではありません。これは、IEEE浮動小数点システムの制限です。忠実な精度を得るには、より高度な数学ライブラリを使用する必要があります。

特定のポイントを超える精度が必要ない場合は、おそらく10進数の方が適しています。ダブルよりも精度が高いです。

于 2009-02-19T20:25:11.573 に答える
0

同様の問題については、次の実装を使用することになります。これは、ほとんどのテストケース(最大5桁の精度)で成功するようです。

public static double roundValue(double rawValue, double valueTick)
{
    if (valueTick <= 0.0) return 0.0;

    Decimal val = new Decimal(rawValue);
    Decimal step = new Decimal(valueTick);
    Decimal modulo = Decimal.Round(Decimal.Divide(val,step));

    return Decimal.ToDouble(Decimal.Multiply(modulo, step));
}
于 2009-04-22T08:25:02.717 に答える
0

結果は、strict:FP IEEE 754から予想されるよりも正確な場合があります。これは、HWが計算に多くのビットを使用するためです。C#仕様この記事を参照してください

Javaにはstrictfpキーワードがあり、C++にはコンパイラスイッチがあります。.NETでそのオプションが恋しい

于 2010-01-12T01:50:13.607 に答える