递归分割错误

时间:2013-12-01 16:29:31

标签: c gcc recursion polynomial-math

所以我写了一个使用递归来计算几个数学函数的标题。包括余弦函数和指数函数(e ^ x)。现在余弦函数工作正常,但即使两者都使用相同的递归过程,e ^ x也会产生分段错误。所以这是我创建的头文件中的代码“c_math.h”:

#define PI 3.141592

static unsigned int n;


................

uint32_t Factorial(unsigned int p)
    {

        if(p==0){

            return(1);

        }else if(p>0){

            return p*Factorial(p-1);

        }       

    }; 


double EXP(double x)
    {

      int    N = n;
      double F = (double)Factorial(n);

      if(n==0){

           return (1.0);

      }else{

        return EXP(x)+(Pow(x,N)/F);

      }


    }

double cosine(double x)
{

    int    N = (2*n);
        double F = (double)(Factorial(2*n)*(-1^n));

    if(n==0){

        return(1.0);

    }else if(n==1){


      return 1+(Pow(x,2)/2);

    }else if(n>1){

      return cosine(x)+(Pow(x,N)/F);


    }

};


double cos(double x){

  bool halt = false;
  double COS;

  n = 0;


  while(halt==false){

     int    N = (2*n);
     double F = (double)(Factorial(2*n)*(-1^n));

     COS = cosine(x);

     if(abs(Pow(x,N)/F)<=0.0001){

            halt = true;

     }else{

         n++;
     }
  }

  return COS;

}

double e(double x){

      bool halt = false;
      double E;

      n = 0;


      while(halt==false){

        int    N = n;
        double F = (double)(Factorial(n));

        E = EXP(x);

        if(abs(Pow(x,N)/F)<=0.0001){

                halt = true;

         }else{

             n++;
         }
      }

      return E;

 }

带有main函数的.c文件:

include <stdio.h>
#include <cmath.h>


int main()
{

  printf("\n");
  printf("cos(2.2) = %4.6f\n",cos(2.2));
  printf("\n");
  printf("e(2.2) = %4.6f\n",e(2.2));
  printf("\n");

}

在我编译它然后从终端提示符执行之后,输出如下所示:

zermacr0yd@DALEK /usr/lib/gcc/x86_64-linux-gnu/4.7.3/include $ ./mathtest

cos(2.2) = -0.588501

Segmentation fault

因此,您可以看到余弦函数按预期工作,但是e ^ x会产生分段错误。现在函数e ^ x严格地增加x> 1。对于x <0并严格减小0,但在数学上,幂级数应该收敛于x的所有值,这意味着最终当系列索引n变得足够高时,第n项的值应该低于0.0001。那么这里发生了什么?

4 个答案:

答案 0 :(得分:2)

您的所有函数都使用变量n,我假设它是全局声明的,但仅在e中本地定义。您应为每个函数提供n的本地定义:int n = 0;

答案 1 :(得分:1)

double EXP(double x) {
    /* other code that doesn't change x */
    if(n==0) {
        return 1.0;
    } else {
        return EXP(x) + /* other code */;
    }
}

假设我们想要计算EXP(2)。 EXP开始运行,转到第二个return语句,再次调用EXP(2)。 其中再次调用EXP(2)。 其中再次调用EXP(2)。 其中再次调用EXP(2)。等

递归仅在函数最终停止递归时有效。

答案 2 :(得分:1)

Unix或POSIX标准定义了一个名为bc的工具,它是一个(非常基本的)多精度命令行计算器。随之而来的是一个数值库,它为exp,cos和sin等提供了明确的实现。研究有效,精确的算法。该联机帮助页,例如在     http://www.gnu.org/software/bc/manual/html_mono/bc.html#SEC18 包含从exp(x)行开始的define e(x)的实现。

基本上,要使Taylor系列工作,首先必须尽可能地将参数减小到接近零。 bc主要使用减半和平方的技术。对于sin和cos,也可以使用周期性和对称性。

可以在

找到完整的bc库
http://code.metager.de/source/xref/gnu/bc/1.06/bc/libmath.b

答案 3 :(得分:1)

余弦泰勒系列的一个严肃的实现是

#include<stdio.h>
#include<math.h>

double cos_taylor(double x) {
  double mxx=-x*x, a=1, c=0;
  unsigned int k=1;
  while(1+a!=1) {
    c+=a;
    a*=mxx/(k++)/(k++);
  }
  return c;
}

int main() {
  double x;
  for(x=-0.5; x<3.2; x+=0.1)
    printf(" x=%10.7f \t math.cos(x)=%20.16g \t taylor.cos(x)=%20.16g\n", 
            x, cos(x), cos_taylor(x));
  return 0;
}