用GCC编译的C系列泰勒级数计算程序

时间:2013-10-10 17:53:17

标签: c gcc 64-bit ubuntu-12.04 32-bit

我在C中编写了一个程序,用于计算函数exp(x)在x的各种值的近似值,有些是正数,有些是负数。我的问题如下:

  1. 尽管之前我能够在序列中包含151个术语, 现在,即使在第140届,该系列也会爆发exp(100)。 之后我用代码搞砸了更多,现在系列爆炸了 甚至在130学期。除此之外我还用了很长时间 数字格式加倍,以允许大的阶乘 计算和显示。怎么能解释这个现象呢? 有时连续执行代码后我得到了结果 近似我检查的函数的实际值 Wolfram Alpha。
  2. 我听说“for”循环被证明效率低下;你有没有 记住“for”循环的替代方案?我很乐意尝试 尽可能多地实施它们。
  3. 我想以科学格式显示输出但格式 说明者(我不确定这个术语)不允许我这样做。 我在printf语句中使用的说明符是%g。我怎么能拥有 输出以科学格式显示?
  4. 根据我使用的硬件和软件,这是最大的 我能得到什么?
  5. 我还得到了分段错误(核心转储)错误而不是 显示x = -100。这背后可能是什么原因?
  6. 感谢您的贡献。我感谢任何帮助和建议。

    P.S:我在64位硬件上使用GCC编译,但在32位Ubuntu 12.04 LTS(a.k.a Precise Pangolin)上编译。

    #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.
    //The upper index controls the accuracy of the Taylor Series, so
    //it is suitable to make it an adjustable parameter. However, after
    //a certain value of p the series become infinitely large to be 
    //represented by the computer; hence we terminate the series at 
    //the 151th term. 
    int p = 150;
    long double series[13][p];
    int i, k;
    //We only define the Taylor series for positive values of the exponent, and
    //later we will use these values to calculate the reciprocals. This is done
    //in this manner to avoid the ambiguity introduced into the sum due to terms
    //alternating in sign.
    long double sum[6] = { 0 };
    for (i = 0; i <= 6;i++) {
    
            for (k = 0; k <= p; k++){
            series[i][k] = pow(x[i], k)/( factorial(k));
            sum[i] += series[i][k];
    }
    printf("Approximation for x = %Lf is %Lf \n", x[i], sum[i]);
    }
    //For negative numbers -taking into account first negative number is
    //in the 8th position in the x array and still denoting the approximation
    long double approx[5] = { 0 };
    for (i = 7; i <= 12;i++) {
        approx[i - 7] = 1 / sum[i - 7];
        printf("Approximation for x = %Lf is %Lf \n", x[i], approx[i - 7]);
    }
    //printf("%Lf \n", factorial(3));
    //The above line was introduced to test if the factorial function
    //was functioning properly.
    }
    

1 个答案:

答案 0 :(得分:2)

回答你的一些问题。

1我的日食代码没有爆炸。

2除了可能过多的迭代之外,我认为使用for循环没有固有的低效率。

3使用"%Le"作为科学格式。

4您可以获得的最大精度将是LDBL_EPSILON 1.取决于您不知道的系统(可能是1个功率(2,64))。记住精度是相对的,而不是绝对的。

5分段错误可能是由于approx[5]造成的。 @Grijesh Chauhan

建议

-15添加到long double x[13+1] = { 1, 5, 10, 15, 20, 50, 100, -1, -5, -10, -15, -20, -50, -100 };。更改其他各种13 s。

添加返回错误条件:
if (n < 0) { printf("Factorial is not defined for a negative number \n"); return 0; }

更改为long double approx[5+1+1] = { 0 };

添加返回main()

如果您首先添加小条款,则会获得更好的数值结果。这通常意味着撤消for (k = 0; k <= p; k++)循环。

int main() {
  long double x[13+1] = { 1, 5, 10, 15, 20, 50, 100, -1, -5, -10, -15, -20, -50, -100 };
  int p = 150;
  long double series[13+1][p];
  int i, k;

  long double sum[6+1] = { 0 };
  for (i = 0; i <= 6; i++) {
    for (k = 0; k <= p; k++) {
      series[i][k] = pow(x[i], k) / (factorial(k));
      sum[i] += series[i][k];
    }
    printf("Approximation for x = %Le is %Le %e\n", x[i], sum[i], exp(x[i]));
  }

  long double approx[7] = { 0 };
  for (i = 7; i <= 12; i++) {
    approx[i - 7] = 1 / sum[i - 7];
    printf("Approximation for x = %Le is %Le %e\n", x[i], approx[i - 7], exp(x[i]));
  }
  return 0;
}