web-dev-qa-db-ja.com

浮動小数点の不正確性のため、Unittest(時々)が失敗する

3次元空間の点を表すクラスVectorがあります。このベクトルには、normalize(self, length = 1)になるようにベクトルを拡大/縮小するメソッドlength == vec.normalize(length).lengthがあります。

このメソッドのユニットテスト時々は、浮動小数点数の不正確さのために失敗します。私の質問は、メソッドが正しく実装されているときにこのテストが失敗しないことをどのように確認できますか? withoutおおよその値をテストすることは可能ですか?



追加情報

_    def testNormalize(self):
        vec = Vector(random.random(), random.random(), random.random())
        self.assertEqual(vec.normalize(5).length, 5)
_

このsometimesは、結果として_AssertionError: 4.999999999999999 != 5_または_AssertionError: 5.000000000000001 != 5_になります。

:浮動小数点の問題は_Vector.length_プロパティまたはVector.normalize()にある可能性があることを認識しています。

57
Niklas R

1)テストが機能することを確認するにはどうすればよいですか?

assertAlmostEqualassertNotAlmostEqualを使用します。

公式ドキュメント から:

assertAlmostEqual(first, second, places=7, msg=None, delta=None)

差を計算し、指定された小数点以下の桁数(デフォルトは7)に丸め、ゼロと比較することにより、1番目と2番目がほぼ等しいことをテストします

2)おおよその値をテストせずにそれを行うことは可能ですか?

本質的にいいえ.

浮動小数点の問題 はバイパスできないため、vec.normalizeで指定された結果を「丸め」るか、ほぼ等しい結果を受け入れる必要があります(2つとも近似値です) )。

101
Rik Poggi

浮動小数点値を使用することで、小さな可能性のある不正確さを受け入れます。したがって、テストでは、計算された値が次のような許容範囲内にあるかどうかをテストする必要があります。

theoreticalValue - epsilon < normalizedValue < theoreticalValue + epsilon

ここで、epsilonは、浮動小数点の不正確さによる変動を許容できると定義する非常に小さな値です。

1つの可能性は、すべての入力、すべての中間計算の結果、および出力がfloatで正確に表現できるテストケースに関数を適用することです。

説明する:

In [2]: import math

In [4]: def norm(x, y):
   ...:     return math.sqrt(x*x + y*y)
   ...: 

In [6]: norm(3, 4) == 5
Out[6]: True

これがどれほど実用的かはわかりませんが...

1
NPE

一般に、フロートの等価性を主張するべきではありません。代わりに、結果が特定の範囲内にあることを確認してください、例えば:

self.assertTrue(abs(vec.normalize(5).length - 5) < 0.001)
1
Thomas Lötzer