【问题标题】:Best method for limiting float precision comparison in Python doctest在 Python doctest 中限制浮点精度比较的最佳方法
【发布时间】:2019-03-28 16:36:43
【问题描述】:

我正在开发一个 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,所以我不知道这是否可能或如何进行。想法?

【问题讨论】:

    标签: python floating-point doctest


    【解决方案1】:

    我花时间查看doctest 并想出了以下内容。它似乎适用于我的floats 的所有格式化方式,但我绝对会感谢有关如何使其更健壮、如何传递所有选项等的建议。(在我的情况下,它特别容易,因为 所有我的文档字符串测试都是浮点数或浮点数列表,所以我没有测试其他用例。)


    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)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-28
      • 1970-01-01
      相关资源
      最近更新 更多