如何对浮点输出进行单元测试? - 蟒蛇

alv*_*vas 17 python testing floating-point precision unit-testing

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

>>> 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
Run Code Online (Sandbox Code Playgroud)

OS /发行版/机器上相同的完全浮点精度是否相同?

我可以尝试完成并进行单元测试:

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

我也可以做一个断言,log(output)但为了保持固定小数精度,我仍然需要进行舍入或截断.

但是,还有什么其他方式可以解决浮点输出的单元测试?

vau*_*tah 28

floatPython 的精度取决于底层的C表示.从教程/浮点算术:问题和限制,15.1:

今天(2000年11月)几乎所有机器都使用IEEE-754浮点运算,几乎所有平台都将Python浮点数映射到IEEE-754"双精度".


至于测试,更好的想法是使用现有功能,例如TestCase.assertAmostEqual:

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

测试第一第二近似(或不近似)通过计算差,四舍五入到小数点的给定数目相等的地方(默认7),并与零进行比较.如果提供delta而不是地点,第一个第二个之间的差值必须小于或等于(或大于)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
Run Code Online (Sandbox Code Playgroud)

如果你更喜欢坚持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
Run Code Online (Sandbox Code Playgroud)

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


Eug*_*ash 8

unittest.TestCase班有比较彩车具体方法:assertAlmostEqualassertNotAlmostEqual.引用文档:

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

测试第一第二近似(或不近似)通过计算差,四舍五入到小数点的给定数目相等的地方(默认7),并与零进行比较.请注意,这些方法将值四舍五入到给定的小数位数(即round()函数),而不是有效数字.

如果提供delta而不是地点,第一个第二个之间的差值 必须小于或等于(或大于)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
Run Code Online (Sandbox Code Playgroud)

使用这些TestCase.assert*方法优于裸assert语句,因为后者可以在某些情况下进行优化.此外,由这些方法产生的测试失败消息通常提供更多信息.