如何在浮点值中添加/减去纯python中最小的可能值[解释如何不同]?

时间:2013-11-27 23:11:49

标签: python python-2.7

这个问题仅适用于Python程序员。这个问题不重复不起作用 Increment a python floating point value by the smallest possible amount请参阅解释底部。


我想为任何浮点数添加/减去一些最小值,这些值会将此浮点值改为大约mantissa/significant part的一位。如何在纯Python 中有效地计算这么小的数字。

例如我有x:

这样的数组
xs = [1e300, 1e0, 1e-300]

生成最小值的功能是什么?所有断言都应该有效。

for x in xs:
  assert x < x + smallestChange(x)
  assert x > x - smallestChange(x)

考虑1e308 + 1 == 1e308因为1对尾数的确意味着0所以`smallestChange'应该是动态的。

纯Python解决方案将是最好的。


为什么这不是Increment a python floating point value by the smallest possible amount 的重复 - 两个简单的测试证明它的结果无效。

(1)问题在Increment a python floating point value by the smallest possible amount差异中没有解决:

Increment a python floating point value by the smallest possible amount尝试使用此代码

import math
epsilon  = math.ldexp(1.0, -53) # smallest double that 0.5+epsilon != 0.5
maxDouble = float(2**1024 - 2**971)  # From the IEEE 754 standard
minDouble  = math.ldexp(1.0, -1022) # min positive normalized double
smallEpsilon  = math.ldexp(1.0, -1074) # smallest increment for doubles < minFloat
infinity = math.ldexp(1.0, 1023) * 2

def nextafter(x,y):    
    """returns the next IEEE double after x in the direction of y if possible"""
    if y==x:
       return y         #if x==y, no increment

    # handle NaN
    if x!=x or y!=y:
        return x + y       

    if x >= infinity:
        return infinity

    if x <= -infinity:
        return -infinity

    if -minDouble < x < minDouble:
        if y > x:
            return x + smallEpsilon
        else:
            return x - smallEpsilon  

    m, e = math.frexp(x)        
    if y > x:
        m += epsilon
    else:
        m -= epsilon

    return math.ldexp(m,e)  
print nextafter(0.0, -1.0), 'nextafter(0.0, -1.0)'
print nextafter(-1.0, 0.0), 'nextafter(-1.0, 0.0)'

Increment a python floating point value by the smallest possible amount的结果无效:

>>> nextafter(0.0, -1)
0.0

应该是非零的。

>>> nextafter(-1,0)
-0.9999999999999998

应为'-0.9999999999999999'。

(2)没有询问如何添加/减去最小值但被问及如何在特定方向上添加/减去值 - 建议解决方案需要知道x和y。这里只需知道x。

(3)建议Increment a python floating point value by the smallest possible amount中的解决方案不适用于边境条件。

2 个答案:

答案 0 :(得分:2)

>>> (1.0).hex()
'0x1.0000000000000p+0'
>>> float.fromhex('0x0.0000000000001p+0')
2.220446049250313e-16
>>> 1.0 + float.fromhex('0x0.0000000000001p+0')
1.0000000000000002
>>> (1.0 + float.fromhex('0x0.0000000000001p+0')).hex()
'0x1.0000000000001p+0'

只需使用相同的符号和指数。

答案 1 :(得分:0)

Mark Dickinson's answer to a duplicate票价要好得多,但仍无法为参数(0, 1)提供正确的结果。

这可能是纯Python解决方案的一个很好的起点。然而,在所有情况下完全正确并不容易,因为有很多极端情况。所以你应该有一个非常好的单元测试套件来覆盖所有角落的情况。

只要有可能,您应该考虑使用基于经过充分测试的C运行时函数的解决方案之一(即通过ctypesnumpy)。

你提到某个地方你担心numpy的内存开销。但是,这个函数对你的工作集的影响非常小,当然不是几兆字节(可能是虚拟内存或私有字节。)