python - 在 Python doctest 中限制浮点精度比较的最佳方法
问题描述
我正在开发一个 Python 版本的库,该库有其他版本,结果已经确定。因此,我的文档字符串中有几行,例如
>>> air_f(0,0,0,0.9,300.,1.)
-95019.5943231
精度在所有版本都应同意的范围内。如果我doctest
在此代码上运行,它期望的值-95019.59432308903
是一致的,但精度更高。在另一种情况下,8.50371537341e-04
被拒绝而支持0.0008503715373413415
,它的精度只有 1 位,但格式不同。
我知道一些处理这个问题的方法。我可以检查所有数字并将其更改为完全精度,或者在每个数字之前添加打印格式语句以仅匹配精度。问题是库中 50 多个单独的文件中的每一个都可以包含数十行这样的行,并且每个文件的特定格式字符串都不同。我看过numtest,但我不知道它是否成熟(而且我在安装它时遇到了麻烦)。
我希望有一些方法可以扩大建设
if __name__ == '__main__':
import doctest
doctest.testmod()
这样就doctest
使用了较弱的浮点相等性测试。将其添加到 50 个文件中比更改 1000 多行更易于管理。不过我不熟悉doctest
,所以我不知道这是否可能或如何进行。想法?
解决方案
我花了一些时间看doctest
并想出了以下内容。它似乎适用于我float
的 s 的所有格式化方式,但我肯定会感谢有关如何使其更健壮、如何传递所有选项等的建议。(在我的情况下,它特别容易,就像我所有的文档字符串一样测试将是浮点数或浮点数列表,所以我没有测试其他用例。)
import doctest
def extractsigfmt(numstr):
"""Find a standard formatter from a string.
From a string representing a float, find the number of
significant digits and return a string formatter to standardize
its representation.
"""
# Pull out the digits term, removing newline and accounting
# for either E or e in exponential notation
digs = numstr.lower().rstrip('\n').split('e')[0]
# Separate from decimal point, removing sign and leading zeros
res = digs.split('.')
if len(res) == 1:
l, r = res, ''
else:
l, r = res
l = l.lstrip(' -+0')
nsig = len(l) + len(r)
# Create a standardized exponential formatter
fmt = '{:+' + '{0:d}.{1:d}'.format(nsig+6,nsig-1) + 'e}'
return fmt
# Create new OutputChecker class
class fltOutputChecker(doctest.OutputChecker):
"""OutputChecker customized for floats.
Overrides check_output to compare standardized floats.
"""
def check_output(self,want,got,optionflags):
"""Check whether actual output agrees with expected.
Return True iff the actual output agrees with the expected
output within the number of significant figures of the
expected output.
"""
fmt = extractsigfmt(want)
want_std = fmt.format(float(want))
got_std = fmt.format(float(got))
return (want_std == got_std)
def testfun(n):
"""Function to test new OutputChecker on.
>>> testfun(0)
-6.96239965190e+05
>>> testfun(1)
8.01977741e-10
>>> testfun(2)
-95019.5943231
>>> testfun(3)
0.164195952060
>>> testfun(4)
-0.687329742959e-3
>>> testfun(5)
0.876543210e3
"""
testlist = [-696239.9651898777,8.01977740740741e-10,
-95019.59432308903,0.1641959520603997,
-0.0006873297429586108,876.54320956893102]
return testlist[n]
# Construct and run doctest on this function
finder = doctest.DocTestFinder()
dtlist = finder.find(testfun)
checker = fltOutputChecker()
runner = doctest.DocTestRunner(checker)
for dt in dtlist:
runner.run(dt)
results = runner.summarize(verbose=True)
推荐阅读
- ios - 使用 UICollectionView 为单元格加载不同的高度
- c++ - 如何在 C++ 中将数字添加到字符串的末尾?
- jquery - jQuery - onClick 获取此属性 id 的等于变量 html 的内容
- azure - 我可以关闭 Azure 应用服务以节省 azure 的成本吗?
- spring-security - 如何通过 Gradle 安装快照 jar?
- c# - 为什么 TaglibSharp 无法读取我的 Id3v2 标签?
- go - MaxActive / wait 可能不起作用,仍在创建数千个连接
- python - 数据类型有问题。不能在整数和(函数?)之间使用 > 运算符
- android - 如何使背景覆盖 recyclerView?
- ios - 边框颜色没有改变