我有一种情况,即除以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中运行良好。
建议?
答案 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)
我建议这样做的原因是,如果您多次执行此功能,则在尝试除法之前,如果值为零,则不必浪费时间进行每次迭代检查。
修改强>:
我比较了try
与if
函数的速度:
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。