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

时间:2015-10-18 15:09:09

标签: python unit-testing testing floating-point precision

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

>>> 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

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

我可以尝试完成这样的单元测试:

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

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

但是,另一种方式应该是pythonically处理浮点输出的单元测试?

2 个答案:

答案 0 :(得分:16)

Python中float的精度取决于底层的C表示。来自Tutorial/Floating Point Arithmetic: Issues and Limitations, 15.1

  

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

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

  

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

     

测试第一个第二个大约(或不是大约)   等于计算差异,舍入到给定的数量   decimal places (默认为7),并与零进行比较。如果提供 delta 而不是 places ,那么 first second 之间的差异必须小于或等于(或大于) 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

答案 1 :(得分:5)

unittest.TestCase类具有比较浮点数的特定方法:assertAlmostEqualassertNotAlmostEqual。引用文档:

  

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

     

测试第一个第二个大约(或不是大约)   等于计算差异,舍入到给定的数量   decimal places (默认为7),并与零进行比较。请注意这些   方法将值舍入到给定的小数位数(即   比如round()函数)而不是有效数字

     

如果提供了 delta 而不是 places 那么之间的区别   第一个第二个必须小于或等于(或大于) 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

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