-2

So I wrote a header that uses recursion to compute several mathematical functions. Including the cosine function and exponential function( e^x). Now the cosine functions works just fine but e^x produces a segmentation fault even though both use the same recursive procedure. So here is the code from the header file I created "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;

 }

The .c file with the main function:

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");

}

After I compile it and then execute from the terminal prompt, the output looks like this:

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

cos(2.2) = -0.588501

Segmentation fault

So as you can see the Cosine function works as it should but e^x produces a segmentation fault. Now the function e^x is strictly increasing for x > 0 and strictly decreasing for x < 0, but mathematically the power series should converge for all values of x which means that eventually when the series index n becomes high enough, the value of the nth term should fall below 0.0001. So what is going on here?

Mr X
  • 336
  • 1
  • 6
  • 22
  • This would't even compile! `};`? – haccks Dec 01 '13 at 16:32
  • And if it would compile, it wouldn't produce the claimed output. – Oswald Dec 01 '13 at 16:38
  • It seems pretty unlikely, to say the least, that a call to `cosine(x)` whose recursive step is to call `cosine(x)` without ever changing the value of `x` will ever terminate. – Tim Pierce Dec 01 '13 at 16:45
  • GUYS: I omitted an additional function: cos(x) which calls the cosine(x) function. It has an accumulator variable COS, which starts at n = 0 and outputs 1.0, but as n increases it calls the cosine(x) which adds the next term of the power series to COS. – Mr X Dec 02 '13 at 05:31

4 Answers4

2

All your functions are using a variable n which I'm assuming is declared globally but only defined locally in e. You should provide a local definition of n for each function: int n = 0;.

  • 1
    It's clearly an error that `n` isn't defined in each function, but it doesn't look as though just declaring `int n = 0;` will fix the code. There's a lot more wrong here than just that. – Tim Pierce Dec 01 '13 at 16:48
  • qwrrty: I just edited the post because the variable n is a global variable(type unsigned int). Sorry for not including that. The cosine function works but the exponential doesn't. – Mr X Dec 02 '13 at 02:52
1
double EXP(double x) {
    /* other code that doesn't change x */
    if(n==0) {
        return 1.0;
    } else {
        return EXP(x) + /* other code */;
    }
}

Let's say we want to calculate EXP(2). EXP starts running, gets to the second return statement, and calls EXP(2) again. Which calls EXP(2) again. Which calls EXP(2) again. Which calls EXP(2) again. Etc.

Recursion only works if the function eventually stops recursing.

user253751
  • 57,427
  • 7
  • 48
  • 90
  • That is EXACTLY how the cosine functions works and for some reason it produces a valid output without any segmentation faults. I suspect the issues is the fact that e^x is a non-periodic function. – Mr X Dec 02 '13 at 05:24
  • What is n? Is n equal to 1? Your cosine function does not recurse if n == 1. – user253751 Dec 02 '13 at 07:15
  • Btw, the factorial function works because Factorial(4) calls Factorial(3) which calls Factorial(2) which calls Factorial(1) which calls Factorial(0) which does not recurse. – user253751 Dec 02 '13 at 07:17
  • immibis: n = 0 initially for the cos function. – Mr X Dec 02 '13 at 15:22
  • Then your cos function always returns 1? (What do you mean "initially"? When does it change?) – user253751 Dec 04 '13 at 22:52
  • No it does not. The cos() function calls the cosine repeatedly by starting with the initial value of 1.0 and adding successive terms of the power series to the accumulator variable until the power series term has a value < 0.0001. – Mr X Dec 05 '13 at 19:43
  • There's nothing in the cos() function that changes n, so if n is 0, then cos(anything) returns 1. – user253751 Dec 07 '13 at 06:07
1

Unix or the POSIX standard defines a tool named bc, which is a (very basic) multi-precision command line calculator. With it comes a numerical library that provides explicit implementations for exp, cos and sin and others. Study that for efficient, precise algorithms. The manpage, for instance at http://www.gnu.org/software/bc/manual/html_mono/bc.html#SEC18 contains the implementation for exp(x) starting at the line define e(x).

Basically, for the Taylor series to work you first have to reduce the argument as close to zero as possible. bc mainly uses the technique of halving-and-squaring. For sin and cos the periodicity and symmetry can also be used.

The full bc library can be found at

http://code.metager.de/source/xref/gnu/bc/1.06/bc/libmath.b
Lutz Lehmann
  • 25,219
  • 2
  • 22
  • 51
1

A no-nonsense implementation of the cosine Taylor series is

#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;
}
Lutz Lehmann
  • 25,219
  • 2
  • 22
  • 51