单元测试因浮点数精度问题(有时)失败
我有一个类叫做 Vector,它表示三维空间中的一个点。这个向量有一个方法 normalize(self, length = 1)
,这个方法可以把向量缩放到指定的长度,也就是说,调用这个方法后,向量的长度会变成 length == vec.normalize(length).length
。
这个方法的单元测试有时候会失败,原因是浮点数的精度问题。我的问题是,如何确保这个测试在方法正确实现时不会失败?有没有可能做到不测试近似值呢?
补充信息:
def testNormalize(self):
vec = Vector(random.random(), random.random(), random.random())
self.assertEqual(vec.normalize(5).length, 5)
这有时候会导致出现 AssertionError: 4.999999999999999 != 5
或者 AssertionError: 5.000000000000001 != 5
的错误。
注意:我知道浮点数的问题可能出现在 Vector.length
属性或者 Vector.normalize()
方法中。
4 个回答
1
一般来说,你不应该直接比较浮点数是否相等。相反,你应该检查结果是否在某个范围内,比如:
self.assertTrue(abs(vec.normalize(5).length - 5) < 0.001)
4
使用浮点数值时,你需要接受一个小的可能误差。因此,你的测试应该检查计算出来的值是否在一个可以接受的范围内,比如:
theoreticalValue - epsilon < normalizedValue < theoreticalValue + epsilon
这里的 epsilon
是一个你自己定义的非常小的值,用来表示由于浮点数不精确而允许的变化范围。
110
1) 我怎么能确保测试有效呢?
可以使用 assertAlmostEqual
和 assertNotAlmostEqual
这两个方法。
根据官方文档的说明:
assertAlmostEqual(first, second, places=7, msg=None, delta=None)
这个方法是用来测试两个数是否大致相等的。它通过计算这两个数的差值,四舍五入到指定的小数位数(默认是7位),然后和零进行比较。
2) 有没有办法不测试近似值呢?
基本上是没有的。
因为浮点数的问题是无法避免的,所以你要么对 vec.normalize
的结果进行“四舍五入”,要么接受一个近似相等的结果(这两种方法都是一种近似处理)。