12

我有一种情况,除以 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

4 回答 4

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
于 2013-04-26T00:13:50.297 回答
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方法更快,至少在我的机器上。

于 2013-04-26T00:16:55.560 回答
3

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

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/ba * (1/b)并实现1/bvia copysign()。当它的参数为 时,乘法不会抛出0*inf,而是正确地产生 NAN。

于 2019-04-12T14:58:23.307 回答
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。

于 2013-04-26T06:07:01.500 回答