是否有一个容易实现的erf()为Python实现?

时间:2009-01-19 12:10:59

标签: python math

我可以实现错误功能,erf,我自己,但我不愿意。是否有一个没有外部依赖项的python包,其中包含此函数的实现?我找到this但这似乎是一些更大的包的一部分(甚至不清楚哪一个!)。

9 个答案:

答案 0 :(得分:61)

自v.2.7起。标准 math 模块包含 erf 功能。这应该是最简单的方法。

http://docs.python.org/2/library/math.html#math.erf

答案 1 :(得分:46)

我推荐SciPy用于Python中的数值函数,但如果你想要一些没有依赖关系的函数,那么对于所有输入,这里的错误误差​​小于1.5 * 10 -7

def erf(x):
    # save the sign of x
    sign = 1 if x >= 0 else -1
    x = abs(x)

    # constants
    a1 =  0.254829592
    a2 = -0.284496736
    a3 =  1.421413741
    a4 = -1.453152027
    a5 =  1.061405429
    p  =  0.3275911

    # A&S formula 7.1.26
    t = 1.0/(1.0 + p*x)
    y = 1.0 - (((((a5*t + a4)*t) + a3)*t + a2)*t + a1)*t*math.exp(-x*x)
    return sign*y # erf(-x) = -erf(x)

该算法来自Handbook of Mathematical Functions,公式7.1.26。

答案 2 :(得分:24)

我建议你下载numpy(在python中有效率矩阵)和scipy(使用numpy的Matlab工具箱替代品)。 erf功能在于scipy。

>>>from scipy.special import erf
>>>help(erf)

您也可以使用pylab中定义的erf函数,但这更倾向于使用numpy和scipy绘制计算结果。如果你想要一体机 安装这些软件,您可以直接使用Python Enthought distribution

答案 3 :(得分:8)

可以在mpmath模块(http://code.google.com/p/mpmath/

中找到纯python实现

来自doc字符串:

>>> from mpmath import *
>>> mp.dps = 15
>>> print erf(0)
0.0
>>> print erf(1)
0.842700792949715
>>> print erf(-1)
-0.842700792949715
>>> print erf(inf)
1.0
>>> print erf(-inf)
-1.0

对于大型真实x\mathrm{erf}(x)非常接近1 迅速::

>>> print erf(3)
0.999977909503001
>>> print erf(5)
0.999999999998463

错误函数是奇函数::

>>> nprint(chop(taylor(erf, 0, 5)))
[0.0, 1.12838, 0.0, -0.376126, 0.0, 0.112838]

:func:erf实现任意精度评估和 支持复数::

>>> mp.dps = 50
>>> print erf(0.5)
0.52049987781304653768274665389196452873645157575796
>>> mp.dps = 25
>>> print erf(1+j)
(1.316151281697947644880271 + 0.1904534692378346862841089j)

相关功能

另请参阅:func:erfc,对于大型x更准确, 和:func:erfi给出了反导数 \exp(t^2)

菲涅耳积分:func:fresnels和:func:fresnelc 也与错误功能有关。

答案 4 :(得分:6)

为了回答我自己的问题,我最终使用了以下代码,改编自我在网络上其他地方找到的Java版本:

# from: http://www.cs.princeton.edu/introcs/21function/ErrorFunction.java.html
# Implements the Gauss error function.
#   erf(z) = 2 / sqrt(pi) * integral(exp(-t*t), t = 0..z)
#
# fractional error in math formula less than 1.2 * 10 ^ -7.
# although subject to catastrophic cancellation when z in very close to 0
# from Chebyshev fitting formula for erf(z) from Numerical Recipes, 6.2
def erf(z):
    t = 1.0 / (1.0 + 0.5 * abs(z))
        # use Horner's method
        ans = 1 - t * math.exp( -z*z -  1.26551223 +
                            t * ( 1.00002368 +
                            t * ( 0.37409196 + 
                            t * ( 0.09678418 + 
                            t * (-0.18628806 + 
                            t * ( 0.27886807 + 
                            t * (-1.13520398 + 
                            t * ( 1.48851587 + 
                            t * (-0.82215223 + 
                            t * ( 0.17087277))))))))))
        if z >= 0.0:
            return ans
        else:
            return -ans

答案 5 :(得分:6)

我有一个执行10 ^ 5个erf调用的函数。在我的机器上......

scipy.special.erf让它的时间为6.1秒

erf数学函数手册需要8.3s

erf Numerical Recipes 6.2需要9.5秒

(三张平均值,代码取自上面的海报)。

答案 6 :(得分:4)

针对那些旨在提高性能的人的一个注意事项:如果可能的话,进行矢量化。

import numpy as np
from scipy.special import erf

def vectorized(n):
    x = np.random.randn(n)
    return erf(x)

def loopstyle(n):
    x = np.random.randn(n)
    return [erf(v) for v in x]

%timeit vectorized(10e5)
%timeit loopstyle(10e5)

给出结果

# vectorized
10 loops, best of 3: 108 ms per loop

# loops
1 loops, best of 3: 2.34 s per loop

答案 7 :(得分:0)

SciPy具有erf函数的实现,请参见scipy.special.erf

答案 8 :(得分:0)

Python's math.erf function documentation 开始,它在近似值中最多使用 50 个术语:

Implementations of the error function erf(x) and the complementary error
   function erfc(x).
   Method: we use a series approximation for erf for small x, and a continued
   fraction approximation for erfc(x) for larger x;
   combined with the relations erf(-x) = -erf(x) and erfc(x) = 1.0 - erf(x),
   this gives us erf(x) and erfc(x) for all x.
   The series expansion used is:
      erf(x) = x*exp(-x*x)/sqrt(pi) * [
                     2/1 + 4/3 x**2 + 8/15 x**4 + 16/105 x**6 + ...]
   The coefficient of x**(2k-2) here is 4**k*factorial(k)/factorial(2*k).
   This series converges well for smallish x, but slowly for larger x.
   The continued fraction expansion used is:
      erfc(x) = x*exp(-x*x)/sqrt(pi) * [1/(0.5 + x**2 -) 0.5/(2.5 + x**2 - )
                              3.0/(4.5 + x**2 - ) 7.5/(6.5 + x**2 - ) ...]
   after the first term, the general term has the form:
      k*(k-0.5)/(2*k+0.5 + x**2 - ...).
   This expansion converges fast for larger x, but convergence becomes
   infinitely slow as x approaches 0.0.  The (somewhat naive) continued
   fraction evaluation algorithm used below also risks overflow for large x;
   but for large x, erfc(x) == 0.0 to within machine precision.  (For
   example, erfc(30.0) is approximately 2.56e-393).
   Parameters: use series expansion for abs(x) < ERF_SERIES_CUTOFF and
   continued fraction expansion for ERF_SERIES_CUTOFF <= abs(x) <
   ERFC_CONTFRAC_CUTOFF.  ERFC_SERIES_TERMS and ERFC_CONTFRAC_TERMS are the
   numbers of terms to use for the relevant expansions. 

#define ERF_SERIES_CUTOFF 1.5
#define ERF_SERIES_TERMS 25
#define ERFC_CONTFRAC_CUTOFF 30.0
#define ERFC_CONTFRAC_TERMS 50

   Error function, via power series.
   Given a finite float x, return an approximation to erf(x).
   Converges reasonably fast for small x.