限制python doctest中的浮点精度比较的最佳方法

时间:2018-10-24 09:52:19

标签: python floating-point doctest

我正在研究库的Python版本,该库的其他版本具有公认的结果。因此,我的文档字符串中包含诸如

>>> air_f(0,0,0,0.9,300.,1.)
-95019.5943231

精度在所有版本应达到的范围内。如果我在此代码上运行doctest,它将期望值-95019.59432308903一致,但精度更高。在另一种情况下,8.50371537341e-04被拒绝,而0.0008503715373413415被拒绝,后者if __name__ == '__main__': import doctest doctest.testmod() 仅具有多一位精度,但格式不同。

我知道几种解决方法。我可以将所有数字更改为完全精度,或者在每个数字之前添加打印格式语句以仅匹配精度。问题在于,库中的50多个单独文件中的每个文件都可以包含许多这样的行,并且每个文件的特定格式字符串都不同。我见过numtest,但是我不知道它是否成熟(另外,我在安装它时遇到了麻烦)。

我希望有一些方法可以扩大建筑

doctest

,以便doctest使用较弱的浮点相等测试。将其添加到50个文件中比更改1000条以上的单行要容易得多。但是,我不熟悉<Personal isUpdated="1"> <Legal_Name> <Country>France</Country> <First_Name>.....</First_Name> <Last_Name>...</Last_Name> </Legal_Name> <Citizenship > <Citizenship_Status_ID>yyy</Citizenship_Status_ID> </Citizenship> <Gender>1</Gender> <Date_of_Birth >1988-07-31</Date_of_Birth> <Country_of_Birth>xxxx</Country_of_Birth> <City_of_Birth >xxxx</City_of_Birth> <Marital_Status>C</Marital_Status> <Nationality>xxxx</Nationality> <Last_Medical_Exam_Date >xxxx</Last_Medical_Exam_Date> ,所以我不知道这是否可行或如何进行。有想法吗?

1 个答案:

答案 0 :(得分:0)

我花时间看了doctest并提出了以下建议。它似乎可以对float进行格式化的所有方式都有效,但是我绝对希望您对如何使其更健壮,如何传递所有选项等提出建议。(就我而言,这特别容易,因为我的文档字符串测试的 all 全部都是float或float列表,所以我没有测试其他用例。)


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)