单元测试因浮点数精度问题(有时)失败

64 投票
4 回答
27546 浏览
提问于 2025-04-17 10:37

我有一个类叫做 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) 我怎么能确保测试有效呢?

可以使用 assertAlmostEqualassertNotAlmostEqual 这两个方法。

根据官方文档的说明:

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

这个方法是用来测试两个数是否大致相等的。它通过计算这两个数的差值,四舍五入到指定的小数位数(默认是7位),然后和零进行比较。

2) 有没有办法不测试近似值呢?

基本上是没有的。

因为浮点数的问题是无法避免的,所以你要么对 vec.normalize 的结果进行“四舍五入”,要么接受一个近似相等的结果(这两种方法都是一种近似处理)。

撰写回答