如何对浮点数输出进行单元测试?- Python

42

假设我正在为一个返回浮点数的函数编写单元测试,我可以按照我的机器完全精度来进行:

>>> import unittest
>>> def div(x,y): return x/float(y)
... 
>>>
>>> class Testdiv(unittest.TestCase):
...     def testdiv(self):
...             assert div(1,9) == 0.1111111111111111
... 
>>> unittest.main()
.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

在不同的操作系统、发行版和计算机上,浮点数的完整精度是否相同?

我可以尝试四舍五入并进行单元测试,例如:

>>> class Testdiv(unittest.TestCase):
...     def testdiv(self):
...             assert round(div(1,9),4) == 0.1111
... 
>>>

我也可以使用log(output)来进行断言,但为了保持固定小数精度,我仍然需要四舍五入或截断。

但是,对于浮点数输出,Python中还有哪些其他优雅的单元测试方式呢?

2个回答

61

Python中float类型的精度取决于底层C语言表示。根据Tutorial/Floating Point Arithmetic: Issues and Limitations, 15.1

几乎所有的现代计算机(截至2000年11月)都使用IEEE-754浮点算法,几乎所有平台将Python中的浮点数映射到IEEE-754“双精度”。


关于测试,更好的方法是使用现有的功能,例如TestCase.assertAlmostEqual

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

通过计算差异、四舍五入到指定数量的小数位(默认为7位)并与零比较,以测试firstsecond是否近似相等或不近似相等。如果提供了delta而不是places,则firstsecond之间的差异必须小于或等于(或大于)delta

示例:

import unittest

def div(x, y): return x / float(y)

class Testdiv(unittest.TestCase):
    def testdiv(self):
        self.assertAlmostEqual(div(1, 9), 0.1111111111111111)
        self.assertAlmostEqual(div(1, 9), 0.1111, places=4)

unittest.main() # OK

如果您更喜欢使用 assert 语句,您可以使用 math.isclose(Python 3.5+):

import unittest, math

def div(x, y): return x / float(y)

class Testdiv(unittest.TestCase):
    def testdiv(self):
        assert math.isclose(div(1, 9), 0.1111111111111111)

unittest.main() # OK

math.close 的默认相对容差是1e-09,"这确保了两个值在大约9个十进制数字内是相同的。"有关math.close的更多信息,请参见PEP 485


如何对具有浮点值的两个列表进行单元测试? - Devharsh Trivedi

19
unittest.TestCase 类有特定的方法可以比较浮点数:assertAlmostEqualassertNotAlmostEqual。引用文档说明如下:

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

测试 firstsecond 是否大约(或不大约)相等,方法是计算它们之间的差异,四舍五入到给定的小数位数(默认为7),并与零进行比较。注意,这些方法将值四舍五入到给定的小数位数(即像round()函数一样),而不是四舍五入到指定的有效数字。

如果使用 delta 而不是 places,则 firstsecond 之间的差异必须小于或等于(或大于)delta

因此,可以像这样测试函数:

self.assertAlmostEqual(div(1, 9), 0.1111111111111111)  # round(a-b, 7) == 0
self.assertAlmostEqual(div(1, 9), 0.1111, 4)           # round(a-b, 4) == 0

顺便提一下,除非你使用pytest作为测试运行器,否则应该使用TestCase.assert*方法代替裸露的assert语句,因为这些方法产生的测试失败消息通常更具信息性。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接