Numpy中避免“复杂除零”错误(与cmath相关)

时间:2016-01-08 11:51:47

标签: python numpy divide-by-zero cmath

我希望在计算中避免使用ZeroDivisionError: complex division by zero,在该例外情况下获取nan

让我用一个简单的例子来陈述我的问题:

from numpy import *
from cmath import *

def f(x) :
    x = float_(x) 
    return 1./(1.-x)

def g(x) :
    x = float_(x)
    return sqrt(-1.)/(1.-x)

f(1.)   # This gives 'inf'.
g(1.)   # This gives 'ZeroDivisionError: complex division by zero'.

我打算获得g(1.) = nan,或者至少是一个中断计算的错误。 第一个问题:我该怎么做?

重要的是,我喜欢修改函数内部的代码(例如,插入异常条件,如this answer中所做的那样),而是将其保留在当前表格(如果可能,甚至删除x = float_(x)行,如下所述)。 原因是我正在使用包含许多函数的长代码:我希望它们都能避免ZeroDivisionError而不需要进行大量更改。

我被迫插入x = float_(x)以避免ZeroDivisionError中的f(1.)第二个问题:是否有一种方法可以抑制此行但仍然可以f(1.) = inf而不修改定义f的所有代码?

编辑:

我已经意识到使用cmathfrom cmath import *)会导致错误。 没有它,我得到g(1.) = nan,这就是我想要的。 但是,我需要在我的代码中使用它。 所以现在第一个问题变成了以下内容:使用cmath时如何避免“复杂除零”?

编辑2:

在阅读答案之后,我做了一些改变,我简化了问题,越来越接近这一点:

import numpy as np                            
import cmath as cm                            

def g(x) :                                    
    x = np.float_(x)                         
    return cm.sqrt(x+1.)/(x-1.)    # I want 'g' to be defined in R-{1}, 
                                   # so I have to use 'cm.sqrt'. 

print 'g(1.) =', g(1.)             # This gives 'ZeroDivisionError: 
                                   # complex division by zero'.

问题:如何避免ZeroDivisionError不修改我的函数代码g

3 个答案:

答案 0 :(得分:1)

我希望函数能够自己处理错误,但如果没有,那么你可以在调用函数时这样做(我相信这比修改函数更有用)。

try:
    f(1.)   # This gives 'inf'.
except ZeroDifivisionError:
    None    #Or whatever
try:
    g(1.)   # This gives 'ZeroDivisionError: complex division by zero'.
except ZeroDifivisionError:
    None    #Or whatever

或者,正如您所提到的答案所述,请使用numpy数字调用您的函数:

f(np.float_(1.))
g(np.float_(1.))

=======
在我的机器上,这个确切的代码给了我一个警告,没有错误。 我不认为有可能得到你想要的东西而不会发现错误......

def f(x):
    return 1./(1.-x)

def g(x):
    return np.sqrt(-1.)/(1.-x)

print f(np.float_(1.))
>> __main__:2: RuntimeWarning: divide by zero encountered in double_scalars
>>inf

print g(np.float_(1.))
>> __main__:5: RuntimeWarning: invalid value encountered in sqrt
>>nan

答案 1 :(得分:1)

我仍然不明白为什么你需要使用cmath。如果期望复杂输出,请在x内输入np.complex_,然后使用np.sqrt

import numpy as np

def f(x):
    x = np.float_(x)
    return 1. / (1. - x)

def g(x):
    x = np.complex_(x)
    return np.sqrt(x + 1.) / (x - 1.)

这会产生:

>>> f(1.)
/usr/local/bin/ipython3:3: RuntimeWarning: divide by zero encountered in double_scalars
  # -*- coding: utf-8 -*-
Out[131]: inf

>>> g(-3.)
Out[132]: -0.35355339059327379j

>>> g(1.)
/usr/local/bin/ipython3:3: RuntimeWarning: divide by zero encountered in cdouble_scalars
  # -*- coding: utf-8 -*-
/usr/local/bin/ipython3:3: RuntimeWarning: invalid value encountered in cdouble_scalars
  # -*- coding: utf-8 -*-
Out[133]: (inf+nan*j)

当然,缺点是函数g总是最终为您提供复杂的输出,如果您将其结果反馈回{{1},这可能会导致问题例如,因为 现在类型转换为浮动,依此类推......也许你应该只是在任何地方输入复制。但这取决于你需要在更大规模上实现的目标。

修改

事实证明,只有在需要时才能让f返回复合体。使用numpy.emath

g

这现在可以提供你所期望的,只在必要时转换为复合体。

import numpy as np

def f(x):
    x = np.float_(x)
    return 1. / (1. - x)

def g(x):
    x = np.float_(x)
    return np.emath.sqrt(x + 1.) / (x - 1.)

答案 2 :(得分:0)

出现错误是因为您的程序正在使用sqrt库中的cmath函数。这是一个很好的例子,说明为什么你应该避免(或者至少要小心)使用from library import *导入整个库。

例如,如果你反转import语句,那么你就没有问题了:

from cmath import *
from numpy import *

def f(x):
    x = float_(x) 
    return 1./(1.-x)


def g(x) :
    x = float_(x)
    return sqrt(-1.)/(1.-x)

现在g(1.)会返回nan,因为sqrt使用numpy函数(可以处理负数)。但这仍然是不好的做法:如果你有一个大文件,那么不清楚使用哪个sqrt

我建议始终使用import numpy as npimport cmath as cm等命名导入。然后,不会导入函数sqrt,要定义g(x),您需要编写np.sqrt(或cm.sqrt)。

但是,您注意到您不想更改您的功能。在这种情况下,您只应从您需要的每个库中导入这些函数,即

from cmath import sin  # plus whatever functions you are using in that file
from numpy import sqrt, float_

def f(x):
    x = float_(x) 
    return 1./(1.-x)


def g(x) :
    x = float_(x)
    return sqrt(-1.)/(1.-x)

不幸的是,你不能轻易摆脱转换为numpy float_,因为python浮点数与numpy浮点数不同,所以这种转换需要在某个时刻发生。