Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compiling some else's C program that uses math.h

Hi I have the following function called zeroin I'd like to compile and link in with a Cpp file but I can't get past the first step of compiling the c file. The function is called zeroin.c I obtained from here. I have put the file in it's own directory, cd'd to it, and since it uses math.h I have used gcc with the -lm flag to make sure the library is linked in.

gcc -Wall -O zeroin.c -o zeroin -lm

However I get the following errors:

zeroin.C:50:15: error: 'ax' was not declared in this scope
zeroin.C:50:18: error: 'bx' was not declared in this scope
zeroin.C:50:21: error: 'f' was not declared in this scope
zeroin.C:50:23: error: 'tol' was not declared in this scope
zeroin.C:50:26: error: expression list treated as compound expression in initialiser [-fpermissive]
zeroin.C:51:1: error: expected ',' or ';' before 'double'
zeroin.C:55:1: error: expected unqualified-id before '{' token

I've included the code for the C code function below - I don't really know C very well and am only trying to compile it so as to use it to find roots for functions in a C++ file I have. How can I solve these errors?

Thanks, Ben.

#include "math.h"

double zeroin(ax,bx,f,tol)      /* An estimate to the root  */
double ax;              /* Left border | of the range   */
double bx;                  /* Right border| the root is seeked*/
double (*f)(double x);          /* Function under investigation */
double tol;             /* Acceptable tolerance     */
{
  double a,b,c;             /* Abscissae, descr. see above  */
  double fa;                /* f(a)             */
  double fb;                /* f(b)             */
  double fc;                /* f(c)             */

  a = ax;  b = bx;  fa = (*f)(a);  fb = (*f)(b);
  c = a;   fc = fa;

  for(;;)       /* Main iteration loop  */
  {
    double prev_step = b-a;     /* Distance from the last but one*/
                    /* to the last approximation    */
    double tol_act;         /* Actual tolerance     */
    double p;               /* Interpolation step is calcu- */
    double q;               /* lated in the form p/q; divi- */
                    /* sion operations is delayed   */
                    /* until the last moment    */
    double new_step;            /* Step at this iteration       */

    if( fabs(fc) < fabs(fb) )
    {                               /* Swap data for b to be the    */
    a = b;  b = c;  c = a;          /* best approximation       */
    fa=fb;  fb=fc;  fc=fa;
    }
    tol_act = 2*EPSILON*fabs(b) + tol/2;
    new_step = (c-b)/2;

    if( fabs(new_step) <= tol_act || fb == (double)0 )
      return b;             /* Acceptable approx. is found  */

                /* Decide if the interpolation can be tried */
    if( fabs(prev_step) >= tol_act  /* If prev_step was large enough*/
    && fabs(fa) > fabs(fb) )    /* and was in true direction,   */
    {                   /* Interpolatiom may be tried   */
    register double t1,cb,t2;
    cb = c-b;
    if( a==c )          /* If we have only two distinct */
    {               /* points linear interpolation  */
      t1 = fb/fa;           /* can only be applied      */
      p = cb*t1;
      q = 1.0 - t1;
    }
    else                /* Quadric inverse interpolation*/
    {
      q = fa/fc;  t1 = fb/fc;  t2 = fb/fa;
      p = t2 * ( cb*q*(q-t1) - (b-a)*(t1-1.0) );
      q = (q-1.0) * (t1-1.0) * (t2-1.0);
    }
    if( p>(double)0 )       /* p was calculated with the op-*/
      q = -q;           /* posite sign; make p positive */
    else                /* and assign possible minus to */
      p = -p;           /* q                */

    if( p < (0.75*cb*q-fabs(tol_act*q)/2)   /* If b+p/q falls in [b,c]*/
        && p < fabs(prev_step*q/2) )    /* and isn't too large  */
      new_step = p/q;           /* it is accepted   */
                    /* If p/q is too large then the */
                    /* bissection procedure can     */
                    /* reduce [b,c] range to more   */
                    /* extent           */
    }

    if( fabs(new_step) < tol_act )  /* Adjust the step to be not less*/
      if( new_step > (double)0 )    /* than tolerance       */
    new_step = tol_act;
      else
    new_step = -tol_act;

    a = b;  fa = fb;            /* Save the previous approx.    */
    b += new_step;  fb = (*f)(b);   /* Do step to a new approxim.   */
    if( (fb > 0 && fc > 0) || (fb < 0 && fc < 0) )
    {                           /* Adjust c for it to have a sign*/
      c = a;  fc = fa;                  /* opposite to that of b    */
    }
  }

}

--EDIT--

Thank you for everyone's suggestions, I've changed the format to ANSI format and changed EPSILON to DBL_EPSILON and also altered #include"math.h" to say #include - the updated function (is included below). However if I try to compile this time:

$gcc -Wall zeroin.c -o zeroin -lm 
zeroin.c: In function 'zeroin':
zeroin.c:78:17: error: 'DBL_EPSILON' undeclared (first use in this function)
zeroin.c:78:17: note: each undeclared identifier is reported only once for each function it appears in
zeroin.c:116:7: warning: suggest explicit braces to avoid ambiguous 'else' [-Wparentheses]

Am is there maybe another library I need for DBL_EPSILON if it's saying that it's not defined?

Thanks, Ben.

#include <math.h>

double zeroin(double ax, double bx, double(*f)(double x), double tol)       /* An estimate to the root */
{
  double a,b,c;             /* Abscissae, descr. see above  */
  double fa;                /* f(a)             */
  double fb;                /* f(b)             */
  double fc;                /* f(c)             */

  a = ax;  b = bx;  fa = (*f)(a);  fb = (*f)(b);
  c = a;   fc = fa;

  for(;;)       /* Main iteration loop  */
  {
    double prev_step = b-a;     /* Distance from the last but one*/
                    /* to the last approximation    */
    double tol_act;         /* Actual tolerance     */
    double p;               /* Interpolation step is calcu- */
    double q;               /* lated in the form p/q; divi- */
                    /* sion operations is delayed   */
                    /* until the last moment    */
    double new_step;            /* Step at this iteration       */

    if( fabs(fc) < fabs(fb) )
    {                               /* Swap data for b to be the    */
        a = b;  b = c;  c = a;          /* best approximation       */
        fa=fb;  fb=fc;  fc=fa;
    }
    tol_act = 2*DBL_EPSILON*fabs(b) + tol/2;
    new_step = (c-b)/2;

    if( fabs(new_step) <= tol_act || fb == (double)0 )
    {
        return b;               /* Acceptable approx. is found  */
    }

                /* Decide if the interpolation can be tried */
    if( fabs(prev_step) >= tol_act  /* If prev_step was large enough*/
    && fabs(fa) > fabs(fb) )    /* and was in true direction,   */
    {                   /* Interpolatiom may be tried   */
    register double t1,cb,t2;
    cb = c-b;
    if( a==c )          /* If we have only two distinct */
    {               /* points linear interpolation  */
      t1 = fb/fa;           /* can only be applied      */
      p = cb*t1;
      q = 1.0 - t1;
    }
    else                /* Quadric inverse interpolation*/
    {
      q = fa/fc;  t1 = fb/fc;  t2 = fb/fa;
      p = t2 * ( cb*q*(q-t1) - (b-a)*(t1-1.0) );
      q = (q-1.0) * (t1-1.0) * (t2-1.0);
    }
    if( p>(double)0 )       /* p was calculated with the op-*/
      q = -q;           /* posite sign; make p positive */
    else                /* and assign possible minus to */
      p = -p;           /* q                */

    if( p < (0.75*cb*q-fabs(tol_act*q)/2)   /* If b+p/q falls in [b,c]*/
        && p < fabs(prev_step*q/2) )    /* and isn't too large  */
      new_step = p/q;           /* it is accepted   */
                    /* If p/q is too large then the */
                    /* bissection procedure can     */
                    /* reduce [b,c] range to more   */
                    /* extent           */
    }

    if( fabs(new_step) < tol_act )  /* Adjust the step to be not less*/
      if( new_step > (double)0 )    /* than tolerance       */
    new_step = tol_act;
      else
    new_step = -tol_act;

    a = b;  fa = fb;            /* Save the previous approx.    */
    b += new_step;  fb = (*f)(b);   /* Do step to a new approxim.   */
    if( (fb > 0 && fc > 0) || (fb < 0 && fc < 0) )
    {                           /* Adjust c for it to have a sign*/
      c = a;  fc = fa;                  /* opposite to that of b    */
    }
  }

}
like image 999
Ward9250 Avatar asked Feb 06 '14 11:02

Ward9250


2 Answers

This code uses the ancient pre-standard style of function signature, with the types of the parameters after the parameter list.

Change

double zeroin(ax,bx,f,tol)      /* An estimate to the root  */
double ax;              /* Left border | of the range   */
double bx;                  /* Right border| the root is seeked*/
double (*f)(double x);          /* Function under investigation */
double tol;             /* Acceptable tolerance     */
{

to:

double zeroin(double ax, double bx, double (*f)(double), double tol)
{

There's surely a way to make gcc accept the old style, but unless you're worried about merge conflicts from upstream changes, you may as well just update it :-)

like image 117
Steve Jessop Avatar answered Oct 30 '22 20:10

Steve Jessop


It looks like the filename has a capitalised extension, .C, which makes GCC think that it's C++ rather than C. The code is in an ancient dialect of C (known as "K&R style") which isn't compatible with C++.

Rename the file to zeroin.c, or specify the language on the command line with -x c.

Alternatively, if you need to use a compiler that doesn't understand K&R syntax, you could change the function header to use modern syntax:

double zeroin(double ax, double bx, double(*f)(double x), double tol)
{
    // code here
}

The remaining problem is the use of EPSILON; in a modern C library, that's called DBL_EPSILON.

like image 33
Mike Seymour Avatar answered Oct 30 '22 21:10

Mike Seymour