【问题标题】:Can't calculate e^(-x) for "high" x无法为“高”x 计算 e^(-x)
【发布时间】:2021-02-03 00:41:15
【问题描述】:

这是我的代码:

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 + 条款。在89term 我被困在-8e5 之后 117 我被困在-8.553016433669241e-05 直到600 + term。

【问题讨论】:

  • 它似乎没有卡住我。我尝试了 50,结果为 -7015.776232596799,而 100 结果为 -2.8756582514726483e+26。您确定这些不是预期结果吗?
  • @mulaixi 但这些显然是错误的值。实函数向 0 单调递减,并且始终为正。
  • 我没有考虑函数,是的,你是对的。当我尝试代码时,结果会波动。所以,这些反对票没有意义。 @KonradRudolph 顺便说一句,我没有投反对票。
  • 我进行了编辑,以便更清晰。
  • 不相关,但您在自己内部隐藏了 sum 内置函数和您自己的 fact 函数;另外,您可以使用math.factorial。此外,您的elif 似乎毫无意义:如果之前的if 为假,则循环将结束并且n 将不再使用。

标签: python function exponential taylor-series


【解决方案1】:

如何做得更好:

好吧,我会说对大小可比的正项和负项相加很容易出错,因为它会导致对小数和大数求和,这是众所周知的问题。但是你可以避免它,因为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 一样。

到底哪里出错了:

下表列出了用泰勒级数总结 N 项来近似计算 exp(-30) 的不同方法:

  • 我只是将这些术语计算为浮点数并总结它们。

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

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

  • 最后我自然地计算了 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 的“正确”值。前者的收敛速度比后者快得多。

表格代码:

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)

【讨论】:

    猜你喜欢
    • 2021-01-24
    • 2018-02-19
    • 2020-12-15
    • 1970-01-01
    • 2010-10-24
    • 2020-08-05
    • 2016-01-16
    • 1970-01-01
    • 2017-04-04
    相关资源
    最近更新 更多