如何通过-0.0和0.0得到Python除法分别得到-Inf和Inf?

时间:2013-04-25 23:58:53

标签: python python-2.7 ieee-754 divide-by-zero

我有一种情况,即除以0.0或-0.0是合理的,我希望分别看到+ Inf和-Inf作为结果。似乎Python喜欢抛出

ZeroDivisionError: float division by zero

无论哪种情况。显然,我认为我可以用0.0的测试简单地包装它。但是,我找不到区分+0.0和-0.0的方法。 (仅供参考,您可以通过键入或通过常见计算(例如-1.0 * 0.0)轻松获得-0.0。

IEEE处理这一切非常好,但Python似乎很难隐藏经过深思熟虑的IEEE行为。事实上,0.0 == -0.0实际上是一个IEEE功能,因此Python的行为严重破坏了事情。它在C,Java,Tcl甚至JavaScript中运行良好。

建议?

4 个答案:

答案 0 :(得分:11)

from math import copysign

def divide(numerator, denominator):
    if denominator == 0.0:
        return copysign(float('inf'), denominator)
    return numerator / denominator

>>> divide(1, -0.0)
-inf
>>> divide(1, 0)
inf

答案 1 :(得分:8)

我完全赞同@Mark Ransom,除了我会改用try

def f(a, b):
    try:
        return a / b
    except ZeroDivisionError:
        return copysign(float('inf'), denominator)

我建议这样做的原因是,如果您多次执行此功能,则在尝试除法之前,如果值为零,则不必浪费时间进行每次迭代检查。

修改

我比较了tryif函数的速度:

def g(a, b):
    if b == 0:
        return copysign(float('inf'), b)
    else:
        return a / b

以下是测试:

s = time.time()
[f(10, x) for x in xrange(-1000000, 1000000, 1)]
print 'try:', time.time()-s
s = time.time()
[g(10, x) for x in xrange(-1000000, 1000000, 1)]
print 'if:', time.time()-s

结果如下:

try: 0.573683023453
if: 0.610251903534

这表明try方法更快,至少在我的机器上。

答案 2 :(得分:2)

gmpy2库提供任意精度浮点类型,并允许您控制IEEE-754异常行为。

>>> import gmpy2
>>> from gmpy2 import mpfr
>>> mpfr(1)/mpfr(0)
mpfr('inf')
>>> mpfr(1)/mpfr(-0)
mpfr('inf')
>>> mpfr(1)/mpfr("-0")
mpfr('-inf')
>>> gmpy2.get_context().trap_divzero=True
>>> mpfr(1)/mpfr(0)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
gmpy2.DivisionByZeroError: 'mpfr' division by zero in division

免责声明:我维持gmpy2。

答案 3 :(得分:2)

这是一种可以正确处理所有边缘情况的解决方案,至少据我所知:

def divide(a: float, b: float) -> float:
    try:
        return a/b
    except:
        return a*math.copysign(math.inf, b)

assert divide( 1,  1) ==  1
assert divide( 1, -1) == -1
assert divide(-1,  1) == -1
assert divide(-1, -1) ==  1
assert divide( 1,  0.0) >  1e300
assert divide( 1, -0.0) < -1e300
assert divide(-1,  0.0) < -1e300
assert divide(-1, -0.0) >  1e300
assert math.isnan(divide( 0.0,  0.0))
assert math.isnan(divide( 0.0, -0.0))
assert math.isnan(divide(-0.0,  0.0))
assert math.isnan(divide(-0.0, -0.0))

b为零的情况下,它基本上将除法a/b分成a * (1/b)并通过1/b实现copysign()。当其自变量为0*inf时,乘法不会抛出,而是正确产生NAN。