Ich habe eine Klasse Vector, die einen Punkt im dreidimensionalen Raum darstellt. Dieser Vektor hat eine Methode normalize(self, length = 1)
, die den Vektor nach unten/oben zu length == vec.normalize(length).length
skaliert.
Das unittest für diese Methode manchmal schlägt wegen der Ungenauigkeit von Gleitkommazahlen fehl. Meine Frage ist, wie kann ich sicherstellen, dass dieser Test nicht fehlschlägt, wenn die Methoden korrekt implementiert sind? Ist es möglich,ohneauf einen ungefähren Wert zu testen?
Zusätzliche Information :
def testNormalize(self):
vec = Vector(random.random(), random.random(), random.random())
self.assertEqual(vec.normalize(5).length, 5)
Diesesmanchmalergibt entweder AssertionError: 4.999999999999999 != 5
oder AssertionError: 5.000000000000001 != 5
.
Note: Ich bin mir bewusst, dass das Gleitkomma-Problem in der Vector.length
-Eigenschaft oder in Vector.normalize()
sein kann.
Verwenden Sie assertAlmostEqual
, assertNotAlmostEqual
.
Aus der offiziellen Dokumentation :
assertAlmostEqual(first, second, places=7, msg=None, delta=None)
Testen Sie, dass der erste und der zweite Wert in etwa gleich sind, indem Sie die Differenz berechnen, auf die angegebene Anzahl von Dezimalstellen aufrunden (Standardwert 7) und mit Null vergleichen.
Grundsätzlich Nr.
Die Gleitkomma-Ausgabe kann nicht umgangen werden. Sie müssen entweder das von vec.normalize
angegebene Ergebnis "abrunden" oder ein nahezu gleiches Ergebnis akzeptieren (jeder der beiden Werte ist eine Näherung).
Durch die Verwendung eines Gleitkommawerts akzeptieren Sie eine kleine mögliche Ungenauigkeit. Daher sollten Ihre Tests prüfen, ob der berechnete Wert in einen akzeptablen Bereich fällt, z.
theoreticalValue - epsilon < normalizedValue < theoreticalValue + epsilon
dabei ist epsilon
ein sehr kleiner Wert, den Sie aufgrund einer Ungenauigkeit der Gleitkommazahl für eine Variation als akzeptabel definieren.
Im Allgemeinen sollten Sie keine Gleichheit für Floats geltend machen. Stellen Sie stattdessen sicher, dass das Ergebnis innerhalb bestimmter Grenzen liegt, z.
self.assertTrue(abs(vec.normalize(5).length - 5) < 0.001)
Ich nehme an, eine Möglichkeit besteht darin, die Funktion auf Testfälle anzuwenden, für die alle Eingaben, die Ergebnisse aller Zwischenberechnungen und die Ausgabe durch float
genau darstellbar sind.
Um zu zeigen:
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
Nicht sicher, wie praktisch dies ist ...