/* findroot.c,v 1.1.1.1 1995/02/27 07:38:32 explorer Exp */

/*
 * Copyright (C) 1989, 1991, 1992, 1993 Mark Podlipec, Craig E. Kolb
 * All rights reserved.
 *
 * This software may be freely copied, modified, and redistributed
 * provided that this copyright notice is preserved on all copies.
 *
 * You may not distribute this software, in whole or in part, as part of
 * any commercial product without the express consent of the authors.
 *
 * There is no warranty or other guarantee of fitness of this software
 * for any purpose.  It is provided solely "as is".
 *
 */

#include "libcommon/common.h"

/* 
 * DEBUGGING PURPOSES
 * FR_POD          is for the FindRoot Routine.
 * FR_NEWT_POD     is for the Newton Routine.
 * FR_BI_POD       is for the Bisection Routine.
#define FR_POD
#define FR_NEWT_POD
#define FR_BI_POD
*/

int Newton _PROTO((Float *, Float *, int, Float, Float, Float *));
int Bisection _PROTO((Float *, int, Float, Float, Float *, int));

/* 
 * POLY_SIZE should be set equal to or larger than the highest degree
 * polynomial to be solved by this routine. This structure could've
 * been an argument to FindRoot, thus making it more flexible, but
 * I decided it would be easier just to have it here and not have to worry
 * about it in all the routines that call it.
 *
 * Some space optimization could be done, but I didn't think the savings
 * would be worth the effort.
 *
 */
#define POLY_SIZE 11
#define FR_MAX_ITERATION 32000

typedef struct STRUCT_POLY_STACK {
 Float roots[POLY_SIZE];
 int   valid[POLY_SIZE];
 Float f[POLY_SIZE];
} POLY_STACK;

static POLY_STACK gg[POLY_SIZE];

static int r_loop=0;

#define TRUE  	1
#define FALSE 	0
#define VALID 	1

/*
#define	FR_EPS     1e-8
#define	FR_EPS_2   1e-9 
*/
#define	FR_EPS     1e-7
#define	FR_EPS_2   1e-8
#define	FR_EPS_3   1e-24

/*
 * FR_EPS_BI is the minimun interval size in the Bisection Code.
 *
 * FR_NEWTON_LOOP is the maximum number of iterations before failure
 *                in the Newton code. This was experimentally determined
 *                using blob and cubicspin.
 *
 * FR_BISECTION_LOOP  just a guess. :^)
 *
 */
#define	FR_EPS_BI         1e-12
#define FR_NEWTON_LOOP    14
#define FR_BISECTION_LOOP 200

int pod_mult = 0;
Float fr_new_min;

/*POD TEMP
#define	FRIsZero(x)   ( ((x) > -FR_EPS)   && ((x) < FR_EPS)   )
#define	FRIsZero3(x)  ( ((x) > -FR_EPS_3) && ((x) < FR_EPS_3) )
*/

/*
 * This is used to determine if we're close enough to zero.
 * Zero being defined by  -z < x < z
 */
#define	FR_IsZero(x,z)   ( ((x) > -(z))   && ((x) < (z))   )

/*
 * This is used to determine the sign of x
 */
/*
#define FR_SGN(x)  ( ((x)<0.0)?(-1):(((x)>0.0)?(int)(1):(0)) )
*/
#define FR_SGN(x)  ( ((x)<0.0)?(int)(-1):(int)(1) )

/*
 * Evaluate the degree _Deg polynomial _p at point _x and put
 * the value into _y(note: when calling give _y not &_y)
 */
#define FR_EVALPOLY(_p,_Deg,_x,_y)                               \
{                                                                \
    int _i;                                                      \
    _y = (_p)[(_Deg)];                                           \
    for(_i=((_Deg)-1);_i>=0;_i--)                                \
        _y=(_x)*_y + (_p)[_i];                                   \
}

#define FR_ADD_ROOT(_deg,_root)                                  \
{                                                                \
    int _ix = 0;                                                 \
    while( (gg[(_deg)].valid[_ix] == VALID) && (_ix < (_deg)))   \
        _ix++;                                                   \
    gg[(_deg)].valid[_ix] = VALID;                               \
    gg[(_deg)].roots[_ix] = (_root);                             \
}

/*
 * This is a specialized routine to find the smallest root in the
 * interval a,b. FindRoot will return a 1 if a root is found and
 * a 0 if no roots are found. If a root is found, it's value will
 * be put in *root.
 */ 
int FindRoot(ff, degree, a, b, root, flag)
     Float *ff;		/* array of coefficients of the polynomial
			   ex: 5x^2 - 2x + 3.0   ff[0] =  3.0
			   ff[1] = -2.0
			   ff[2] =  5.0  */
     int degree;	/* the degree of polynomial */
     Float a, b;	/* the interval to look for roots in */
     Float *root;	/* where to put a root if found */
     int flag;		/* Should always be -1 when called. This is
			   used to initialize derivatives the 1st
			   time called but not when FindRoot calls
			   itself subsequently.*/
{
  int loop;
  Float *f1,*f0;
  
  /*
   * Just in case something really goes wrong bomb out before stack space 
   * gets recursivley eaten away. (This happened during initial debug and
   * I can't think a situation that would cause it now but it doesn't hurt.
   */
  if (r_loop > FR_MAX_ITERATION) {
    fprintf(stderr,"FindRoot Error: r_loop=%ld degree=%ld flag=%ld\n",
	    r_loop,degree,flag);
    exit(0);
  }
  
#ifdef FR_POD
  fprintf(stderr," FLAG %ld) <%lf,%lf> c",degree,a,b);
  for(i=degree;i>=0;i--) fprintf(stderr," %lf",ff[i]);
  fprintf(stderr,"\n");
#endif
  

  /* not a valid polynomial as far as we're concerned. */
  if (degree<=0) {
#ifdef FR_POD
    fprintf(stderr,"   FALSE_%ld: degree is <= 0\n",degree);
#endif
    return FALSE;
  }
  
  
  /* 
   * Find Root called for the first time.
   * Calculate all derivatives of the polynomial.
   * and initialize static structure to hold them.
   */
  if (flag < 0) {
    register int i,j;
    
    /*
     * get rid of high order coefficients if they are zero.
     * this can happen with both blob and cubicspin code.
     */
    while( (ff[degree] == 0.0) && (degree) ) degree--;
    
    /* Some useful variables. f0=ff() and f1=ff'(). */
    f0 = gg[degree].f;
    f1 = gg[degree-1].f;
    
    /* Initialize valid flags to !VALID */
    for(i=1; i<POLY_SIZE; i++) 
      for(j=0; j<i; j++) gg[i].valid[j]=0;
    
    /* Initialize and calculate coefficients for all 
     * derivatives of ff() 
     */
    for(i=0;i<=degree;i++) f0[i] = ff[i];
    for(i=degree-1;i>=2;i--) 
      for(j=0;j<=i;j++) 
	gg[i].f[j] = (Float)(j+1) * gg[i+1].f[j+1];
    /* initialize variable that flags runaway recursion. Again
     * I don't believe it will occur, but I won't rule it out.
     */
    r_loop = 1; pod_mult = 0;
    if (flag == -2) {
      Float aa;
      int num;
      
      flag = degree;
      fr_new_min = aa = a;
      num = 0;
      pod_mult = 1; /* multi */
      
#ifdef FR_POD
      fprintf(stderr,"************MULTI FINDROOT START**************\n");
#endif
      while( FindRoot(f0,degree,aa,b,root,flag) ) {
	aa = fr_new_min;
	num++;
	root++;
	r_loop = 1;
      }
#ifdef FR_POD
      fprintf(stderr,"\nFINDROOT found %ld roots\n\n\n",num);
#endif
      return(num);  /* return number found */
    }
    else if (flag == -1) flag = degree; /* and drop through */
    else {
      fprintf(stderr,"FindRoot: Bad flag parameter %ld\n",flag);
      return(0);
    }
  } else {
    /* 
     * Not the 1st time through. Check to see if we've already calculated
     * a valid root for this derivative in this interval from a previous
     * recursive call.
     */
    register int ix;
    r_loop++;
    ix = 0;
    
    /* Some useful variables. f0=ff() and f1=ff'(). */
    f0 = gg[degree].f;
    f1 = gg[degree-1].f;
    
#ifdef FR_POD
    fprintf(stderr,"   POLY_CACHE_%ld: <%lf,%lf> \n",degree,a,b);
#endif
    /* Check the valid flags and if valid, check to see if it
     * is in the current interval
     */
    while( (gg[degree].valid[ix]==VALID) ) {
#ifdef FR_POD
      fprintf(stderr,"         %ld) %lf\n",ix,gg[degree].roots[ix]);
#endif
      if (gg[degree].roots[ix] > (a + FR_EPS_2) ) {
	if (gg[degree].roots[ix] <= b ) {
	  *root = gg[degree].roots[ix];
#ifdef FR_POD
	  fprintf(stderr,"   POLY_CACHE: TRUE_%ld: %lf\n",degree,*root);
#endif
	  if (pod_mult) fr_new_min = *root + FR_EPS;
	  return TRUE;
	}
      }
      ix++;
      /* 
       * If all possible roots at this degree have been 
       * found and none of them are in the interval [a,b] 
       * then return FALSE.
       */
      if (ix >= degree) {
#ifdef FR_POD
	fprintf(stderr,
		"   FALSE_%ld: all found and none in interval\n",degree);
#endif
	return FALSE; 
      }
    } /* end of search for valid roots */
  } /* end of not first time that FindRoot was called */
  
  
  /******************************************************************
   * DEGREE==1
   *
   * If ff() is of degree 1 then it's a simple line.
   */
  if (degree==1) {
    if ( FR_IsZero(f0[1],FR_EPS) ) {
#ifdef FR_POD
      fprintf(stderr,"   FALSE_%ld: slope of line is zero\n",degree);
#endif
      return FALSE;
    }
    else *root = -f0[0]/f0[1];
    
    gg[degree].valid[0] = 1; 
    gg[degree].roots[0] = *root; 
    if (*root > a) {
      if (*root < b) {
#ifdef FR_POD
	fprintf(stderr,"   TRUE_%ld: %lf\n",degree,*root);
#endif
	if (pod_mult) fr_new_min = *root + FR_EPS;
	return TRUE;
      }
    }
#ifdef FR_POD
    fprintf(stderr,"   FALSE_%ld: root %lf not in range\n",degree,root);
#endif
    return FALSE;
  } 
  /******************************************************************
   * DEGREE==2
   *
   * If ff() is of degree 2 then use Quadratic Equation to find roots.
   */
  if (degree==2) {
    register Float t,d0,d1;
    
    d0 = f0[1];
    t = d0*d0 - 4.0 * f0[2]*f0[0];
    
    /* Return FALSE if roots are imaginary. */
    if (FR_SGN(t) == -1) {
#ifdef FR_POD
      fprintf(stderr,"   FALSE_%ld: roots imaginary\n",degree);
#endif
      return FALSE; 
    }
    
    /* There is only one root. */
    if (FR_SGN(t) == 0.0) { 
      /* Note f0[2] was checked for zero above 
       * as gg[degree].f[degree].
       */
      d1 = -d0/(2.0 * f0[2]); 
      
      /* Since for this set of coeff we found 
       * all possible roots, set up static structure 
       * to indicate this.
       */
      gg[degree].valid[0] = VALID;
      gg[degree].valid[1] = VALID;
      gg[degree].roots[0] = d1; 
      gg[degree].roots[1] = d1; 
      if (d1 > a) {
	if (d1 < b) {
	  *root = d1;
#ifdef FR_POD
	  fprintf(stderr,"   TRUE_%ld: %lf\n",degree,*root);
#endif
	  if (pod_mult) fr_new_min = d1 + FR_EPS;
	  return TRUE; 
	} 
      } 
#ifdef FR_POD
      fprintf(stderr,"   FALSE_%ld: 1 root %lf not in range\n",degree,d1);
#endif
      return FALSE;
    }
    
    /* FR_SGN(t) > 0  which means there are two roots */
    t = sqrt(t);
    
    /* If the smallest root has already been found, then it 
     * was not in the current interval [a,b]. So skip this
     * and calculate the larger quadratic root.
     * NOTE: if both of the roots are valid then we wouldn't
     * be here, we would've either returned which ever one was
     * the smallest in the interval [a,b] or returned false.
     */
    if (gg[degree].valid[0]!=VALID) {
      /* Calculate smallest Quadratic root */
      if (f0[2]>0.0) d1= (-d0-t)/(2.0*f0[2]);
      else d1= (-d0+t)/(2.0*f0[2]);
      
#ifdef FR_POD
      fprintf(stderr,"   POD_2: f0[2:0]  %lf %lf %lf\n",f0[2],f0[1],f0[0]);
      fprintf(stderr,"   POD_2: (t %lf) (d0 %lf) (f0[2] %lf) (d1 %lf)\n",
	      t, d0, f0[2], d1 );
#endif
      /* put it in the static structure */
      gg[degree].valid[0] = VALID;
      gg[degree].roots[0] = d1; 
      if (d1 > a) { 
	if (d1 < b) { 
	  *root = d1; 
#ifdef FR_POD
	  fprintf(stderr,"   TRUE_%ld: %lf\n",degree,*root);
#endif
	  if (pod_mult) fr_new_min = d1 + FR_EPS;
	  return TRUE; 
	}
      } /* fall through otherwise and calculate larger */
#ifdef FR_POD
      fprintf(stderr,"   FALL_%ld: %lf not in range.t =%lf\n",degree,*root,t);
#endif
    } /* fall through otherwise and calculate larger */
    
    /* Calculate largest Quadratic root */
    if (f0[2]>0.0) d1= (-d0+t)/(2.0*f0[2]);
    else d1= (-d0-t)/(2.0*f0[2]);
    
    /* put it in the static structure */
    gg[degree].valid[1] = VALID;
    gg[degree].roots[1] = d1; 
    if (d1 > a) {
      if (d1 < b) {
	*root = d1;
#ifdef FR_POD
	fprintf(stderr,"   TRUE_%ld: %lf\n",degree,*root);
#endif
	if (pod_mult)
	  fr_new_min = d1 + FR_EPS;
	return TRUE; 
      }
    }
#ifdef FR_POD
    fprintf(stderr,"   FALSE_%ld: root %le not in range\n",degree,d1);
#endif
    return FALSE;
  } /* end of degree==2 */
  
  /******************************************************************
   * DEGREE>=3
   *
   * Now for the fun stuff.
   *
   * The algorithm being find the smallest root of f'() in the interval
   * [a,b]. This will either be a min or a max(we don't care which). Call
   * this point c. Now evaluate f(a) and f(c). If they are of different
   * signs, the f() has a root in the interal [a,c], use Newton's method
   * to solve. If they are of the same sign, there is no root in [a,c]
   * so move the interval in question to [c,b] and recall FindRoot.
   * Oh, and if there is no min/max then the sign tests apply with a and b
   * in the same way as the applied to a and c.
   *
   * There's some tricky parts, like what happens if there's a root at a?
   * Since this is raytracing, we assume the ray was fired off from a 
   * surface and we didn't quite clear it. So we walk a forward in
   * increments of FR_EPS2 which is smaller than FR_EPS. If after an
   * arbitrary amount, f(a) is still zero, then we return the root at a+.
   * Another situation where this occurs, is when we move the interval
   * from [a,b] to [c,b] and then search for a min/max along the new
   * interval, f'(c) is going to zero and we want the next root, not
   * the one we've already found. So we need to walk the start of the
   * interval in this case as well.
   * Walking might be an overkill, it might only be necessary to jump
   * one arbitrary amount(EPS or 2*EPS). I still need to experimentally
   * decide which is more efficient.
   *
   */
  {
    Float y0,y1,c;
    int diff_ret;
    
    /* find the next root of f'() and store in c */
#ifdef FR_POD
    fprintf(stderr,"   FindRoot_%ld: find root of f'()\n",degree);
#endif
    diff_ret = FindRoot(f1,(degree-1),a,b,&c,flag);
    
    /* Evaluate the polynomial at the beginning of the interval
     * and walk it forward if it is zero
     */
    /*PODTEMP was loop=10, a+=EPS_2 */
    FR_EVALPOLY(f0,degree,a,y0);
    loop=2;
    while( (FR_IsZero(y0,FR_EPS)) && (loop--) ) {
      a += FR_EPS;
      FR_EVALPOLY(f0,degree,a,y0);
    }
    
    
    /*
     * No roots of ff'() in [a,b] so there is no min/max
     */
    if (!diff_ret) {
      /* Evaluate polynomial at point b */
      FR_EVALPOLY(f0,degree,b,y1);
      
      /* if ff(a) and ff(b) have the same sign return false 
       * else use Newton */
      if (FR_SGN(y0) == FR_SGN(y1)) {
#ifdef FR_POD
	fprintf(stderr, "   FALSE_%ld: no roots, fa=%lf,fb=%lf same side\n",
		degree, y0, y1);
#endif
	return FALSE;
      }
#ifdef FR_POD
      fprintf(stderr, "   Newton_%ld: f(a)=%lf,f(b)=%lf diff sides\n",
	      degree, y0, y1);
#endif
      return( Newton(f0,f1,degree,a,b,root) );
    }
    
    /*
     * ff'() does have a root at c where  a < c < b.
     */
    FR_EVALPOLY(f0,degree,c,y1);	
    
    /* 
     * It's possible there could be a root at c. If we just moved
     * on we could miss it, because FindRoot is used to false roots
     * at the start of an interval
     */
    if ( FR_IsZero(y1,FR_EPS) ) {
      *root = c;
      FR_ADD_ROOT(degree,c);
#ifdef FR_POD
      fprintf(stderr,"   TRUE_%ld: %lf root at min/max\n",degree,*root);
#endif
      if (pod_mult)
	fr_new_min = c + FR_EPS;
      return TRUE;
    }
    
    /*
     * if same sign move interval to [c,b] and call FindRoot
     * else there is a root in [a,c] use Newton to solve.
     */
    if (FR_SGN(y0) == FR_SGN(y1)) {
#ifdef FR_POD
      fprintf(stderr, "   FindRoot_%ld: Forward to <min/max(%lf),b>\n",
	      degree, c);
      fprintf(stderr, "                 f(a) = %le  f(c) = %le\n", y0, y1);
#endif
      return(FindRoot(f0,degree,c,b,root,flag));
    } else {
#ifdef FR_POD
      fprintf(stderr, "   Newton_%ld: f(a)=%lf,f(min/max)=%lf diff sides\n",
	      degree, y0, y1);
#endif
      return( Newton(f0,f1,degree,a,c,root) );
    }
  } /* end of degree >= 3 */
} /* end of routine */


/********************************************************************
 *
 * This routine numerically tries to find a root of f0() in the interval
 * [a,b].
 *
 */
int Newton(f0, f1, degree, a, b, root)
     Float *f0;	/* f0() is the polynomial */
     Float *f1;	/* f1() is the 1st derivative of the polynomial */
     int degree; 	/* degree is the degree of the polynomial f0() */
     Float a,b;     /* this is the interval [a,b] to find the roots on */
     Float *root;	/* if a root is found, put here */
{
  register int loop_num, sign_fb;
  register Float y0, y1, x0, xmin, xmax;
  
  a += FR_EPS;    /* move forward */ /* PODTEMP was EPS_2 */
  FR_EVALPOLY(f0, degree, b, y0);
  sign_fb = FR_SGN(y0);
  xmin = a;
  xmax = b;
  
  if (pod_mult) fr_new_min = b;
  
#ifdef FR_NEWT_POD
  fprintf(stderr,"  Newton_%ld <%lf,%lf> \n",degree,a,b);
#endif
  /* loop an arbitrary number of times, if no root is found then
   * give up. In experiments with cubicspin and blob code, The root
   * was either resolved in <18 iterations or it was never(50+) 
   * resolved.
   */
  loop_num = FR_NEWTON_LOOP;
  /* do a bisection to start with in case slope is ~0 at a.
   * this is likely since the interval moves to the min/max's
   * of the derivatives.
   */
  x0 = 0.5 * (a + b);  
  do {
    FR_EVALPOLY(f0,degree,x0,y0);  /* y0 = f(x0) */ 
    /* check to see if we are close enough to zero to
     * call it a success 
     */
#ifdef FR_NEWT_POD
    fprintf(stderr," %ld) y %lf x,a,b %lf %lf %lf  DEG %lx\n",
	    loop_num,y0,x0,a,b,degree);
#endif
    if ( FR_IsZero(y0,FR_EPS) ) { 
      if (FR_SGN(y0) != sign_fb) x0 += FR_EPS;
      if (x0 > a)
	{
	  if (x0<b) {
	    *root = x0; 
	    FR_ADD_ROOT(degree,x0);
#ifdef FR_NEWT_POD
	    fprintf(stderr,"   Newton: TRUE_%ld: %lf\n",degree,*root);
#endif
	    return TRUE; 
	  } 
	} 
#ifdef FR_NEWT_POD
      fprintf(stderr,"   Newton-yes, but no\n");
#endif
      return (Bisection(f0,degree,xmin,xmax,root,sign_fb) );
    }
    
    FR_EVALPOLY(f1,(degree-1),x0,y1);  
    /* 
     * Value of derivative is zero and that's not real good,
     * but it's possible. Revert to bisection method 
     */
    if (FR_IsZero(y1,FR_EPS_3)) {
#ifdef FR_NEWT_POD
      fprintf(stderr,"   Deriv Zero %le\n",y1);
#endif
      return (Bisection(f0,degree,xmin,xmax,root,sign_fb) );
    } else {
      register Float tmp_x;
      tmp_x = x0 - (y0/y1);
      
      /*
       * Newton tunneled out of interval [a,b]. This could 
       * result in skipping over a valid root in the interval
       * and finding a root outside of the interval. 
       * Revert to Bisection Method
       */
      if (tmp_x > b) {
#ifdef FR_NEWT_POD
	fprintf(stderr,"   tunnel out > b %le\n",tmp_x);
#endif
	return (Bisection(f0,degree,xmin,xmax,root,sign_fb) );
      } else if (tmp_x < a) {
#ifdef FR_NEWT_POD
	fprintf(stderr,"   tunnel out < a %le\n",tmp_x);
#endif
	return (Bisection(f0,degree,xmin,xmax,root,sign_fb) );
      }
      if ( FR_SGN(y0) == sign_fb) {
	if (x0 < xmax)  xmax = x0;
      } else {
	if (x0 > xmin)  xmin = x0;
      }
      x0 = tmp_x; 
    }
    loop_num--;
  } while(loop_num);
#ifdef FR_NEWT_POD
  fprintf(stderr,"   FALSE_%ld: NEWTON - too many iterations\n",degree);
#endif
  return (Bisection(f0,degree,a,b,root,sign_fb) );
} /* end of Newton */


/********************************************************************
 * Bisection
 *
 *
 *
 *
 */

int Bisection(f0, degree, orig_a, orig_b, root, sign_fb)
     Float *f0;	          /* f0() is the polynomial */
     int degree;          /* degree is the degree of the polynomial f0() */
     Float orig_a, orig_b;/* this is the interval [a,b] to find the roots on */
     Float *root;         /* if a root is found, put here */
     int sign_fb;         /* sign of f0(b) to prevent problems later */
{
  register int loop_num;
  register Float a, b, fa, fx0, x0, diff, odiff;

  a = orig_a;
  b = orig_b;
  FR_EVALPOLY(f0, degree, a, fa);  /* fa = f(a) */
  
  /* POD TEMP */
  FR_EVALPOLY(f0, degree, b, fx0); 
  if ( FR_SGN(fa) == FR_SGN(fx0) ) {
    
    if (a == b)
      return FALSE;
    if (FR_IsZero(fx0,FR_EPS)) {
      *root = b;
      FR_ADD_ROOT(degree,b);
#ifdef FR_BI_POD
      fprintf(stderr,"   Bisect: TRUE_%ld: wierd %lf\n", degree, b);
#endif
      return TRUE;
    }
#ifdef FR_BI_POD
    fprintf(stderr,"   Bisect: FALSE_%ld: major error %lf\n",degree,b);
#endif
    return FALSE;
  }
  
#ifdef FR_BI_POD
  fprintf(stderr,"Bisection: <a,b> <%lf,%lf> fa %lf ",a,b,fa);
#endif
  diff = b - a;
  odiff =  diff + 1.0; /* force while entry */
  loop_num = FR_BISECTION_LOOP; /* arbitrary */
  while( (diff < odiff) && (loop_num--) ) {
    x0 = 0.5 * (a + b);
    FR_EVALPOLY(f0,degree,x0,fx0);  /* fx0 = f(x0) */
#ifdef FR_BI_POD
    fprintf(stderr,"  x0 %lf fx0 %lf\n",x0,fx0);
#endif
    /*
     * if zero then return TRUE
     */
    if ( FR_IsZero(fx0,FR_EPS) ) {
      if ( (FR_SGN(fx0)) == sign_fb)
	x0 += FR_EPS; 
      if (x0 > orig_a) {
	if (x0 <= orig_b) {
	  *root = x0;
	  FR_ADD_ROOT(degree,x0);
#ifdef FR_BI_POD
	  fprintf(stderr,"   Bisect: TRUE_%ld: %lf\n",degree,*root);
#endif
	  return TRUE;
	}
      }
#ifdef FR_BI_POD
      fprintf(stderr,"   Bisect: FALSE_%ld a\n",degree);
#endif
      return FALSE;
    }
    /*
     * If middle is of a different sign than start,
     * move to lower segment.
     */
    if ( FR_SGN(fa) != FR_SGN(fx0) ) 
      b = x0;
    else { /* else move to upper segment */
      a = x0;
      fa = fx0;
    }
    odiff = diff; diff = b - a;
  }
  if (x0 > orig_a) {
    if (x0 <= orig_b) {
      /*PODTEMP was loop=20 EPS_2 */
      int loop = 2;  
      orig_b -= FR_EPS;
      
      /* try walking root until it's the same sign */
      while( (FR_SGN(fx0) != sign_fb) && (loop--) && (x0 < orig_b) ) {
	x0 += FR_EPS;
	FR_EVALPOLY(f0,degree,x0,fx0);
      }
      
      *root = x0;
      FR_ADD_ROOT(degree,*root);
      
#ifdef FR_BI_POD
      fprintf(stderr,"   Bisect: TRUE_%ld: %lf\n",degree,*root);
#endif
      
      return TRUE;
    }
  }
#ifdef FR_BI_POD
  fprintf(stderr,"   Bisect: FALSE_%ld b\n",degree);
#endif
  return FALSE;
}

