【问题标题】:Taylor Series for Exponential Function exp(-x)指数函数 exp(-x) 的泰勒级数
【发布时间】:2013-10-08 06:10:03
【问题描述】:

我一直在编写泰勒级数的程序,并使用 long double 作为数字格式来计算大数。我的程序对于正指数工作得很好,但在涉及负指数时却失败了。问题是当我为某些 x 计算 exp(-x) 时,我得到了非常大的正数。这背后的原因可能是什么?提前感谢您的帮助。你可以在这里看到我的代码:

#include <stdio.h>
#include <math.h>
//We need to write a factorial function beforehand, since we
//have factorial in the denominators.
//Remembering that factorials are defined for integers; it is
//possible to define factorials of non-integer numbers using
//Gamma Function but we will omit that.
//We first declare the factorial function as follows:
long double factorial (double);
//Long long integer format only allows numbers in the order of 10^18 so 
//we shall use the sign bit in order to increase our range.
//Now we define it,
long double
factorial(double n)
{
//Here s is the free parameter which is increased by one in each step and
//pro is the initial product and by setting pro to be 0 we also cover the
//case of zero factorial.
    int s = 1;
    long double pro = 1;
    if (n < 0)
        printf("Factorial is not defined for a negative number \n");
    else {
    while (n >= s) { 
    pro *= s;
    s++;
    }
    return pro;
    }
}

int main ()
{
    long double x[13] = { 1, 5, 10, 15, 20, 50, 100, -1, -5, -10, -20, -50, -100};
//Here an array named "calc" is defined to store 
//the values of x.

//int k;
////The upper index controls the accuracy of the Taylor Series, so
////it is suitable to make it an adjustable parameter. 
int p = 135;
long double series[13][p];
long double sum = 0;
int i, k;
for (i = 0; i <= 12;i++) {
for (k = 0; k <= p; k++){
    series[i][k] = pow(x[i], k)/( factorial(k));
    sum += series[i][k];
}
printf("Approximation for x = %Lf is %Lf \n", x[i], sum);
}
printf("%Lf \n", factorial(100));
}

【问题讨论】:

  • 当包含两个术语时,问题甚至仍然存在 1 - 1/x -exp(-x) 并且它仍然给出大于 1 + 1/x -exp(x) 的值 - 问题是当 x = 1 时非常明显。
  • 我在您的代码中没有看到可以使用负指数的任何地方。我看到 pow(x[i], k),这基本上意味着 x[i]^k,并且 k 在您的代码中始终是正数。 exp(-x) 是什么意思?

标签: exponential


【解决方案1】:

这只是数值分析的数学主题。 e^x 的 MacLaurin 系列收敛于所有 x,但让我们看看为什么它对 e^(-10) 没有用处。

e^x = 1 + x + x^2/2 + x^3/6 + x^4/24 + x^5/120 + x^6/720 + x^7/5040 + ... +x^n/n! + ...

e^(-10) = 1 - 10 + 100/2 - 1000/6 + 10000/24 -100000/120 + ...

系列中最大的术语是什么? 10^10/10!,大约是 2755.7319224e^(-10) 的真实值是多少 大约是 0.00004539992。将系列加起来会丢失 9 位精度,而您根本没有。

如果你找到e^(10) 并采取倒数,你会相当安全。如果您通过将 (1/e) 乘以 10 次直接计算 e^(-10),那么您也是安全的。但是任何具有交替项且量级可能远大于真实答案的序列都会导致这些问题。

即使对于范围有限的函数,MacLaurin 级数也不会在实践中使用。例如,首先获取三角函数的参数,并使用周期性和三角恒等式将参数减少到区间0 &lt; θ &lt; π/4。然后,人们经常应用切比雪夫近似来均匀地减少误差。在其他情况下,连分数和 Pade 近似值优于三角级数。贝塞尔函数最好通过向后递归来完成。

看一本好的数值分析书。 Forman Acton 的通常有效的数值方法是老式的,但是很好。

【讨论】:

  • 嗯,是的,我有点发现罪魁祸首是交替系列,所以应该不惜一切代价避免它吗?然后最好的方法是计算 e 而不是执行必要的幂运算,但我被要求使用 Taylor 级数(在本例中为 Maclaurin 级数)作为 exp(x)。我认为教练这样做是为了让我们意识到处理交替系列非常危险的事实。
  • 你可能是对的。你为什么不跟踪最大的项(以大小为单位)并将其打印出来。您可以查看 AMS 55(Abromowitz 和 Stegun)或 NIST 的新 DLMF 算法替代品。除了 NIST 是离线的。关闭剧院。
  • 这本书的正确标题是Numerical Methods that Work
【解决方案2】:

你没有把你的总和归零。您只是将每个新结果添加到之前的结果中。

sum = 0; 添加为第一个for 循环中的第一条语句。

道德:始终为应该是函数的内容创建函数。在这种情况下,编写一个单独的 exp_taylor() 函数,而不是仅仅将其内联。

【讨论】:

  • 嗯,我认为这解决了我的问题,但我没能理解你的意思,总是为应该是一个函数的函数创建一个函数。我是否创建了一个或两个不必要的函数?
  • @Vesnog 否 - 您应该创建一个函数,例如long double exp_taylor(double x) 为您计算。这不仅是标准做法,而且发生此错误的可能性要小得多。
  • 哦,我现在明白了。顺便说一句,深夜编程肯定会变得一团糟。
【解决方案3】:

在计算每个系列后,您需要将总和重置为零:

int main ()
{
  long double x[13] = { 1, 5, 10, 15, 20, 50, 100, -1, -5, -10, -20, -50, -100}; 
  const int p = 135;
  long double series[13][p];
  int i, k;
  for (i = 0; i <= 12;i++) {
    long double sum = 0;  // LOOK HERE
    for (k = 0; k <= p; k++){
      series[i][k] = pow(x[i], k)/( factorial(k));
      sum += series[i][k];
    }
    printf("Approximation for x = %Lf is %Lf \n", x[i], sum);
  }
}

另请注意,您正在扩展大约 x=0,并且可以预期 x 远离 0 时会出现重大错误。

【讨论】:

    猜你喜欢
    • 2018-09-13
    • 1970-01-01
    • 1970-01-01
    • 2016-01-24
    • 2014-04-03
    • 2017-06-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多