【问题标题】:Floating Point Modulo Problem浮点取模问题
【发布时间】:2010-02-24 02:33:03
【问题描述】:

我偶然发现了一个非常奇怪的错误。阅读代码中的 cmets 以了解究竟是什么错误,但本质上是一个模 1 的变量返回 1(但它不等于 1!)。我假设有一个显示问题,浮动非常接近一但不完全。但是,它应该模数为零。我不能轻易测试这种情况,因为 (last % 1) != 1.0 !当我尝试将相同的数字插入另一个 python 终端时,一切正常。怎么回事?

def r(k,i,p):
    first = i*p
    last = first + p

    steps = int((i+1)*p) - int(i*p)
    if steps < 1:
        return p
    elif steps >= 1:
        if k == 0:
            return 1 - (first % 1)
        elif k == steps:
            if i == 189:
                print last, 1, type(last), last % 1, last - int(last)
                # Prints: 73.0 1 <type 'float'> 1.0 1.0
                print last % 1 == 1 # Returns False
            if last % 1 == 1.0:
                return 0
            return (last % 1)
        else:
            return 1

【问题讨论】:

    标签: python floating-point floating-accuracy


    【解决方案1】:

    欢迎来到 IEEE754,enjoy your stay

    【讨论】:

    • 您认为减去机器 epsilon 会有所帮助吗? python 将此值显示为 1.0 的事实非常非常无用。我可以处理不精确,但我需要确切地知道它的结局。
    • 它小于一,但足够接近可以四舍五入。您是否要对其取模以使其小于{向上舍入为 1.0 的最大浮点数}?为什么您的应用在其他地方的 floats-close-to-1 上卡住了?
    • 问题是它真的应该溢出到接近于零而不是一的东西。除非我能识别它,否则我无法将其四舍五入。对位图的第 189 行进行例外处理似乎真的很不稳定(特别是如果我将来调整它的大小)。
    • 为什么真的会溢出? 小于 1。为什么浮点数足够接近 1 以在以默认精度显示时四舍五入导致您的问题?
    • 浮点误差累计小于一,但按理说应该略高于或等于一。在应该为零时将一行设置为最大值是一个大问题。
    【解决方案2】:

    打印不显示存储数字的完整精度,您可以使用repr() 来做到这一点

    >>> last=72.99999999999999
    >>> print last, 1, type(last), last % 1, last - int(last)
    73.0 1 <type 'float'> 1.0 1.0
    >>> print last % 1 == 1
    False
    >>> print repr(last), 1, type(last), repr(last%1), repr(last - int(last))
    72.999999999999986 1 <type 'float'> 0.99999999999998579 0.99999999999998579
    >>> 
    

    【讨论】:

    • 在 3.7 中不再适用(也许更早的 3.x 也是如此?)。 print(last, last % 1) 产生 72.99999999999999 0.9999999999999858
    【解决方案3】:

    你应该使用 math.fmod(x, y)。这是http://docs.python.org/library/math.html的摘录:

    "请注意,Python 表达式 x % y 可能不会返回相同的结果。C 标准的意图是 fmod(x, y) 完全(数学上;无限精度)等于 x - n*y for一些整数 n,使得结果与 x 具有相同的符号,并且幅度小于 abs(y)。Python 的 x % y 返回一个带有 y 符号的结果,并且可能无法精确计算浮点参数。例如,fmod (-1e-100, 1e100) 是 -1e-100,但是 Python 的 -1e-100 % 1e100 的结果是 1e100-1e-100,不能完全表示为浮点数,四舍五入到令人惊讶的 1e100 。出于这个原因,函数 fmod() 在处理浮点数时通常是首选,而 Python 的 x % y 在处理整数时是首选。"

    【讨论】:

    • +1 表示一般观点。不过,在这种情况下,我认为这并不重要:如果xy 都是有限的(我没有声称无穷大和nans!)并且是肯定的,x % y 将给出与fmod(x, y) 相同的结果。 (或者,事实上,如果xy 都是负数。)x // y 在这种情况下也会给出准确的结果,只要商不超过2**53
    • 忽略上面关于x // y 的部分:这不是真的。 Python 在内部将x // y 计算为(x - x % y) / y,四舍五入到最接近的整数,(x - x % y) / y 的结果可能有多达 1.5 ulps 的误差。所以x // y 的结果只能保证精确到大约2**51 的商。
    • 是的,你当然是对的,马克(感谢您的慷慨)。 (我想我无论如何都误读了这个问题,并不是因为它使我的答案更加正确。我现在看到这是一个经典的“浮点显示与内部”问题。)
    【解决方案4】:

    您可以尝试math.fmod 函数而不是last % 1,也许它更适合您的问题。 或者你可以在整数空间中重新表述你的问题。

    无论如何,使用相等 == 运算符比较浮点值并不是一个好习惯,因为即使像 0.1 + 0.2 == 0.3 这样看似微不足道的操作也会产生不精确的结果

    【讨论】:

      【解决方案5】:

      如果您需要任意精度,有一些项目可以做到这一点。 gmpy 处理多精度整数,mpmath 看起来不错,bigfloat 包装 MPFR。通过 gnibbler 的回答,您所拥有的可能就足够了,但以防万一。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-06-07
        • 2016-08-28
        • 2016-06-04
        • 2011-02-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多