无法计算 "high" x 的 e^(-x)

Can't calculate e^(-x) for "high" x

这是我的代码:

def fact(y):
    if y == 0:
        fact=1
        return fact
    else:
        fact=1
        for k in range (1, y+1):
            fact = fact * k
        return fact

def e_negative_x(x):
    n=0
    numerical_precesion=1
    numerical_precesion_ideal= 10**(-8)
    while numerical_precesion > numerical_precesion_ideal:
        sum=0
        for i in range (0, n+1):
            ind=((-x)**i)/fact(i)
            if i> 0 & n-i == 0:
                ind_2=((-x)**(i-1))/fact(i-1)
                numerical_precesion_1 = ind_2 - ind
                numerical_precesion = abs(numerical_precesion_1)
            sum = sum + ind
        if   numerical_precesion > numerical_precesion_ideal:
            n += 1
        elif sum < 0:
            n += 1
    return sum

我尝试将此用于 x=0.1;1;10;15 作为练习,我的精度得到了“正确”,但是当我尝试 x=30 时它卡在了 -8e-5(不正确的答案) .我试图增加我的条款,但它仍然停留在 -8e-5,小数位不同,并且在条款大幅增加后根本没有改变。

编辑:-8e-5 是错误的,因为在无穷大这个级数趋于 0。我做了一个无限循环(对于无限项)并让它打印出它有多少项以及它的总和条款。在我关闭之前,我有 600 + 个条件。在 89 学期我被困在 -8e5 之后 117 我被困在 -8.553016433669241e-05 直到 600 + 学期。

如何做得更好:

好吧,我想说的是,对大小相当的正项和负项求和很容易出错,因为它会导致对小数和大数求和,这众所周知是有问题的。但是你可以避免它,因为 exp(-30)=1/exp(30).

1/math.fsum(((30)**n/math.factorial(n) for n in range(0,100+1)))

9.357622968840174e-14

即像你期望的那样积极和小。并且

1/math.fsum(((30)**n/math.factorial(n) for n in range(0,100+1)))-np.exp(-30)

给予

-1.262177448353619e-29

所以我们得到的结果与 numpy 基本相同。

具体错误在哪里:

这里是 table 计算 exp(-30) 的不同方法,用泰勒级数对 N 项求和:

  • 天真的我只是把这些项计算为浮点数并将它们相加。

  • 在分数列中,我做了同样的事情,但使用了 python 的分数而不是浮点除法。

  • 然后我认为在division/muliplication和总结中区分错误会很好。所以我用分数计算了每个被加数,但在求和之前把它们变成了浮点数。

  • 最后我计算了 exp(30) 的值,然后是 1/exp(30) 我称之为 1/e^30_trick.

            native     fractions  float(fraction)  1/e^30_trick
0    1.000000e+00  1.000000e+00     1.000000e+00  1.000000e+00
10   1.212548e+08  1.212548e+08     1.212548e+08  4.187085e-09
20   8.529171e+10  8.529171e+10     8.529171e+10  2.652040e-12
30   3.848426e+11  3.848426e+11     3.848426e+11  1.706501e-13
40   6.333654e+10  6.333654e+10     6.333654e+10  9.670058e-14
50   8.782292e+08  8.782292e+08     8.782292e+08  9.360412e-14
60   1.685584e+06  1.685584e+06     1.685584e+06  9.357627e-14
70   6.225246e+02  6.225247e+02     6.225246e+02  9.357623e-14
80   5.588481e-02  5.595324e-02     5.588481e-02  9.357623e-14
90  -6.697346e-05  1.459487e-06    -6.697346e-05  9.357623e-14
100 -6.843293e-05  1.276217e-11    -6.843293e-05  9.357623e-14
110 -6.843294e-05  9.361706e-14    -6.843294e-05  9.357623e-14
120 -6.843294e-05  9.357623e-14    -6.843294e-05  9.357623e-14

我对结果很满意。因为它表明 naiv 甚至 float(fractions) 方式都很糟糕,所以错误一定是在总结负项和正项时。同样,即使 1/exp(30) 技巧和派系都收敛到 9.357623e-14 的“正确”值。前者比后者收敛快很多

Table代码:

series = pd.Series(np.arange(0,151,10))

@np.vectorize
def naiv(N):
    return math.fsum(((-30)**n/math.factorial(n) for n in range(0,N+1)))

@np.vectorize
def fractions(N):
    return float(sum(Fraction((-30)**n,math.factorial(n)) for n in range(0,N+1)))

@np.vectorize
def float_fractions(N):
    return math.fsum(float(Fraction((-30)**n,math.factorial(n))) for n in range(0,N+1))

@np.vectorize
def one_over_30_trick(N):
    return 1/math.fsum(((30)**n/math.factorial(n) for n in range(0,N+1)))

pd.DataFrame({"native":naiv(series),"fractions":fractions(series),"float(fraction)":float_fractions(series),"1/e^30_trick":one_over_30_trick(series)},index=series)