python中是否有可缩放的互补错误函数?

python中是否有可缩放的互补错误函数?,python,math,mpmath,Python,Math,Mpmath,在matlab中,有一个在我所知道的Python的任何集合中都不可用的函数(numpy、scipy、mpmath等等) 可能还有其他地方可以找到像这样的函数 UPD对于所有认为问题无关紧要的人,请先尝试为参数~30计算此函数 UPD2任意精度是一个很好的解决方法,但如果可能,我宁愿避免它。我需要一个“标准”的机器精度(不多不少)和最大速度可能 UPD3结果是,mpmath给出的结果出人意料地不准确。即使在标准pythonmath工作的地方,mpmath的结果也更糟糕。这使得它毫无价值 UPD4用

在matlab中,有一个在我所知道的Python的任何集合中都不可用的函数(numpy、scipy、mpmath等等)

可能还有其他地方可以找到像这样的函数

UPD对于所有认为问题无关紧要的人,请先尝试为参数~30计算此函数

UPD2任意精度是一个很好的解决方法,但如果可能,我宁愿避免它。我需要一个“标准”的机器精度(不多不少)和最大速度可能

UPD3结果是,
mpmath
给出的结果出人意料地不准确。即使在标准python
math
工作的地方,
mpmath
的结果也更糟糕。这使得它毫无价值

UPD4用于比较不同计算方法的代码

import numpy as np 

def int_erfcx(x):
    "Integral which gives erfcx" 
    from scipy import integrate
    def f(xi):
        return np.exp(-x*xi)*np.exp(-0.5*xi*xi)
    return 0.79788456080286535595*integrate.quad(f,
                           0.0,min(2.0,50.0/(1.0+x))+100.0,limit=500)[0] 

def my_erfcx(x):
    """M. M. Shepherd and J. G. Laframboise, 
       MATHEMATICS OF COMPUTATION 36, 249 (1981)
       Note that it is reasonable to compute it in long double 
       (or whatever python has)
    """
    ch_coef=[np.float128(0.1177578934567401754080e+01),
             np.float128(  -0.4590054580646477331e-02),
             np.float128( -0.84249133366517915584e-01),
             np.float128(  0.59209939998191890498e-01),
             np.float128( -0.26658668435305752277e-01),
             np.float128(   0.9074997670705265094e-02),
             np.float128(  -0.2413163540417608191e-02),
             np.float128(    0.490775836525808632e-03),
             np.float128(    -0.69169733025012064e-04),
             np.float128(      0.4139027986073010e-05),
             np.float128(       0.774038306619849e-06),
             np.float128(      -0.218864010492344e-06),
             np.float128(        0.10764999465671e-07),
             np.float128(         0.4521959811218e-08),
             np.float128(         -0.775440020883e-09),
             np.float128(          -0.63180883409e-10),
             np.float128(           0.28687950109e-10),
             np.float128(             0.194558685e-12),
             np.float128(            -0.965469675e-12),
             np.float128(              0.32525481e-13),
             np.float128(              0.33478119e-13),
             np.float128(              -0.1864563e-14),
             np.float128(              -0.1250795e-14),
             np.float128(                 0.74182e-16),
             np.float128(                 0.50681e-16),
             np.float128(                 -0.2237e-17),
             np.float128(                 -0.2187e-17),
             np.float128(                    0.27e-19),
             np.float128(                    0.97e-19),
             np.float128(                     0.3e-20),
             np.float128(                    -0.4e-20)]
    K=np.float128(3.75)
    y = (x-K) / (x+K)
    y2 = np.float128(2.0)*y
    (d, dd) = (ch_coef[-1], np.float128(0.0))
    for cj in ch_coef[-2:0:-1]:             
        (d, dd) = (y2 * d - dd + cj, d)
    d = y * d - dd + ch_coef[0]
    return d/(np.float128(1)+np.float128(2)*x)

def math_erfcx(x):
    import scipy.special as spec
    return spec.erfc(x) * np.exp(x*x)

def mpmath_erfcx(x):
    import mpmath
    return mpmath.exp(x**2) * mpmath.erfc(x)

if __name__ == "__main__":
    x=np.linspace(1.0,26.0,200)
    X=np.linspace(1.0,100.0,200)

    intY  = np.array([int_erfcx(xx*np.sqrt(2)) for xx in X])
    myY   = np.array([my_erfcx(xx) for xx in X])
    myy   = np.array([my_erfcx(xx) for xx in x])
    mathy = np.array([math_erfcx(xx) for xx in x])
    mpmathy = np.array([mpmath_erfcx(xx) for xx in x])
    mpmathY = np.array([mpmath_erfcx(xx) for xx in X])

    print ("Integral vs exact: %g"%max(np.abs(intY-myY)/myY))
    print ("math vs exact:     %g"%max(np.abs(mathy-myy)/myy))
    print ("mpmath vs math:    %g"%max(np.abs(mpmathy-mathy)/mathy))
    print ("mpmath vs integral:%g"%max(np.abs(mpmathY-intY)/intY))

exit()
对我来说,它给我

Integral vs exact: 6.81236e-16
math vs exact:     7.1137e-16
mpmath vs math:    4.90899e-14
mpmath vs integral:8.85422e-13

显然,
math
在其工作的地方提供了尽可能好的精度,
mpmath
math
工作的地方提供了更大数量级的错误,而对于更大的参数,则提供了更大数量级的错误

我不知道任何标准源是否包含该函数,但您可以直接实现它,至少如果您使用mpmath并且不太担心性能的话:

import math
import mpmath

def erfcx(x):
    return math.exp(x**2) * math.erfc(x)

def erfcx_mp(x):
    return mpmath.exp(x**2) * mpmath.erfc(x)

where = mpmath.linspace(1, 50, 10) + mpmath.linspace(100, 1000, 5)
for x in where:
    try:
        std = erfcx(x)
    except OverflowError:
        std = None
    new = erfcx_mp(x)
    approx = (1/(x*mpmath.pi**0.5))
    print x, std, new, (new-approx)/approx 
产生

1.0 0.427583576156 0.427583576155807 -0.242127843858688
6.44444444444444 0.0865286153111 0.0865286153111425 -0.0116285899486798
11.8888888888889 0.0472890800456 0.0472890800455829 -0.00350053472385845
17.3333333333333 0.032495498521 0.0324954985209682 -0.00165596082986796
22.7777777777778 0.024745497 0.0247454970000106 -0.000960939188986022
28.2222222222222 None 0.0199784436993529 -0.000626572735073611
33.6666666666667 None 0.0167507236463156 -0.000440550710337029
39.1111111111111 None 0.0144205913280408 -0.000326545959369654
44.5555555555556 None 0.0126594222570918 -0.00025167403795913
50.0 None 0.0112815362653238 -0.000199880119832415
100.0 None 0.00564161378298943 -4.99925018743586e-5
325.0 None 0.00173595973189465 -4.73366058776083e-6
550.0 None 0.00102579754728657 -1.6528843659911e-6
775.0 None 0.000727985953393782 -8.32464102161289e-7
1000.0 None 0.000564189301453388 -4.9999925011689e-7

即使在math.*例程溢出时,它的行为也应该如此。mpmath的间隔支持不足以完成这项任务(没有一些黑客,我懒得去做),但对于这一点,我非常确信mpfs就足够了,因为erfcx只是mpmath可以很好地计算的两个方面的产物。

这里有一个简单而快速的实现,在全球范围内提供12-13位数的精度:

from scipy.special import exp, erfc

def erfcx(x):
    if x < 25:
        return erfc(x) * exp(x*x)
    else:
        y = 1. / x
        z = y * y
        s = y*(1.+z*(-0.5+z*(0.75+z*(-1.875+z*(6.5625-29.53125*z)))))
        return s * 0.564189583547756287
来自scipy.special import exp,erfc
def erfcx(x):
如果x<25:
返回erfc(x)*exp(x*x)
其他:
y=1x
z=y*y
s=y*(1.+z*(-0.5+z*(0.75+z*(-1.875+z*(6.5625-29.53125*zаа))
返回s*0.56418958354756287
该库提供对MPFR多精度库的访问。对于正常精度,它几乎比mpmath快5倍

$ py27 -m timeit -s "import mpmath" -s "def erfcx(x):return mpmath.exp(x**2) * mpmath.erfc(x)" "erfcx(30)"
10000 loops, best of 3: 47.3 usec per loop
$ py27 -m timeit -s "import gmpy2" -s "def erfcx(x):return gmpy2.exp(x**2) * gmpy2.erfc(x)" "erfcx(30)"
100000 loops, best of 3: 10.8 usec per loop
这两个库都返回相同的30的结果

>>> import mpmath
>>> import gmpy2
>>> mpmath.exp(30**2) * mpmath.erfc(30)
mpf('0.018795888861416751')
>>> gmpy2.exp(30**2) * gmpy2.erfc(30)
mpfr('0.018795888861416751')
>>> 
免责声明:我维护gmpy2。我正在积极地开发一个新的版本,但是对于这个计算,当前版本应该没有任何问题

编辑:我很好奇调用两个函数而不是一个函数的开销,所以我完全用C实现了一个gmpy2.erfcx(),但仍然使用MPFR来执行计算。进步比我预期的要小。如果您认为erfcx()有用,我可以将其添加到下一个版本中

$ py27 -m timeit -s "import gmpy2" "gmpy2.erfcx(30)"
100000 loops, best of 3: 9.45 usec per loop

一个高度优化的C++实现,用于Erfcx(对于实数和复数参数)最近应该在SciPy版本0.12中。

这个函数现在在Sisty的最新版本中可用,参见./P> <代码> Erfcx()/Cyto>并不难实现,你不觉得吗?这看起来很难实现。@Ayoubi如果你不关心大参数的精度,也许吧。“但我知道。”丹:错了。如果您不关心正确性,那么
erfcx=lambda x:numpy.exp(x**2)*scipy.special.erfc(x)
可能适合您。但总的来说,当你处理浮点值时,这并不是一件小事。你能举一个例子,说明mpmath给出的结果不准确吗?非常令人惊讶的是,它会比标准的python数学模块更糟糕。是的,我正要提到mpmath()作为一个可能的答案。例如,当x=30时,它给出的mpf('0.018795888861416751')与我从倍频程得到的结果相匹配。如果你有特定的速度、精度,或者您没有提到的领域需求,您可能应该将这些内容编辑到您的问题中。不久前,我们做了一些工作,用
cython
设置了
mpmath
,从而实现了一些不错的性能改进。目前,它仅适用于
sage
(),但可以将其拔出或钩住。到目前为止,最快的解决方案是:在我的机器上使用0.73 usec。请注意,下面提到的SciPy 0.12中的C实现比这快了一个数量级。感谢您的回答。如果有更多像这样的函数可用于avois数字问题,那就太好了。还有其他例子。例如,所有库都有拉盖尔多项式,但没有拉盖尔函数(是按指数缩放的拉盖尔多项式)。当我需要时,我必须编写自己的递归实现。当您拥有多项式的快速实现时,编写一个快速实现只需几分钟,但是没有人为scipy和其他人这样做。很可能,它也被认为是“微不足道的”。