Ejemplo n.º 1
1
        /* Max # of iterations */
        /* R_zeroin2() is faster for "expensive" f(), in those typical cases where
         *             f(ax) and f(bx) are available anyway : */
        double R_zeroin2(			        /* An estimate of the root */
            double ax,				        /* Left border | of the range	*/
            double bx,				        /* Right border| the root is seeked*/
            double fa, double fb,	        /* f(a), f(b) */
            R_zeroin_fn f,	                /* Function under investigation	*/
            dynamic info,				    /* Add'l info passed on to f	*/
            ref double Tol,			        /* Acceptable tolerance		*/
            ref int Maxit)
        {
            double a, b, c, fc;             /* Abscissae, descr. see above,  f(c) */
            double tol;
            int maxit;

            a = ax; b = bx;
            c = a; fc = fa;
            maxit = Maxit + 1; tol = Tol;

            /* First test if we have found a root at an endpoint */
            if (fa == 0.0)
            {
                Tol = 0.0;

                Maxit = 0;
                return a;
            }

            if (fb == 0.0)
            {
                Tol = 0.0;
                Maxit = 0;
                return b;
            }

            while (maxit-- != 0)		    /* 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 (Math.Abs(fc) < Math.Abs(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 * Double.Epsilon * Math.Abs(b) + tol / 2;
                new_step = (c - b) / 2;

                if (Math.Abs(new_step) <= tol_act || fb == (double)0)
                {
                    Maxit -= maxit;
                    Tol = Math.Abs(c - b);
                    return b;           /* Acceptable approx. is found	*/
                }

                /* Decide if the interpolation can be tried	*/
                if (Math.Abs(prev_step) >= tol_act  /* If prev_step was large enough*/
                    && Math.Abs(fa) > Math.Abs(fb))
                {   /* and was in true direction,
                                 * Interpolation may be tried	*/
                    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 */
                        q = -q;         /* opposite sign; make p positive */
                    else            /* and assign possible minus to	*/
                        p = -p;         /* q				*/

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

                if (Math.Abs(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, info); /* Do step to a new approxim. */
                if ((fb > 0 && fc > 0) || (fb < 0 && fc < 0))
                {
                    /* Adjust c for it to have a sign opposite to that of b */
                    c = a; fc = fa;
                }

            }
            /* failed! */
            Tol = Math.Abs(c - b);
            Maxit = -1;
            return b;
        }
Ejemplo n.º 2
0
        /*
         * root finder routines are copied from stats/src/zeroin.c
         */
        double R_zeroin(                    /* An estimate of the root */
            double ax,                      /* Left border | of the range	*/
            double bx,                      /* Right border| the root is seeked*/
            R_zeroin_fn f,                  /* Function under investigation	*/
            dynamic info,                   /* Add'l info passed on to f	*/
            ref double Tol,                 /* Acceptable tolerance		*/
            ref int Maxit)                  /* Max # of iterations */
        {
            double fa = f(ax, info);
            double fb = f(bx, info);

            return(R_zeroin2(ax, bx, fa, fb, f, info, ref Tol, ref Maxit));
        }
Ejemplo n.º 3
0
 /* Max # of iterations */
 /*
  * root finder routines are copied from stats/src/zeroin.c
  */
 double R_zeroin(                    /* An estimate of the root */
     double ax,                      /* Left border | of the range	*/
     double bx,                      /* Right border| the root is seeked*/
     R_zeroin_fn f,	                /* Function under investigation	*/
     dynamic info,				    /* Add'l info passed on to f	*/
     ref double Tol,			        /* Acceptable tolerance		*/
     ref int Maxit)
 {
     double fa = f(ax, info);
     double fb = f(bx, info);
     return R_zeroin2(ax, bx, fa, fb, f, info, ref Tol, ref Maxit);
 }
Ejemplo n.º 4
0
        /* R_zeroin2() is faster for "expensive" f(), in those typical cases where
         *             f(ax) and f(bx) are available anyway : */

        double R_zeroin2(                   /* An estimate of the root */
            double ax,                      /* Left border | of the range	*/
            double bx,                      /* Right border| the root is seeked*/
            double fa, double fb,           /* f(a), f(b) */
            R_zeroin_fn f,                  /* Function under investigation	*/
            dynamic info,                   /* Add'l info passed on to f	*/
            ref double Tol,                 /* Acceptable tolerance		*/
            ref int Maxit)                  /* Max # of iterations */
        {
            double a, b, c, fc;             /* Abscissae, descr. see above,  f(c) */
            double tol;
            int    maxit;

            a     = ax; b = bx;
            c     = a; fc = fa;
            maxit = Maxit + 1; tol = Tol;

            /* First test if we have found a root at an endpoint */
            if (fa == 0.0)
            {
                Tol = 0.0;

                Maxit = 0;
                return(a);
            }

            if (fb == 0.0)
            {
                Tol   = 0.0;
                Maxit = 0;
                return(b);
            }

            while (maxit-- != 0)          /* 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 (Math.Abs(fc) < Math.Abs(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 * Double.Epsilon * Math.Abs(b) + tol / 2;
                new_step = (c - b) / 2;

                if (Math.Abs(new_step) <= tol_act || fb == (double)0)
                {
                    Maxit -= maxit;
                    Tol    = Math.Abs(c - b);
                    return(b);           /* Acceptable approx. is found	*/
                }

                /* Decide if the interpolation can be tried	*/
                if (Math.Abs(prev_step) >= tol_act && /* If prev_step was large enough*/
                    Math.Abs(fa) > Math.Abs(fb))
                {   /* and was in true direction,
                     * Interpolation may be tried	*/
                    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 */
                    {
                        q = -q;        /* opposite sign; make p positive */
                    }
                    else               /* and assign possible minus to	*/
                    {
                        p = -p;        /* q				*/
                    }
                    if (p < (0.75 * cb * q - Math.Abs(tol_act * q) / 2) && /* If b+p/q falls in [b,c]*/
                        p < Math.Abs(prev_step * q / 2)) /* and isn't too large	*/
                    {
                        new_step = p / q;                /* it is accepted
                                                          * If p/q is too large then the
                                                          * bisection procedure can
                                                          * reduce [b,c] range to more
                                                          * extent */
                    }
                }

                if (Math.Abs(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, info); /* Do step to a new approxim. */
                if ((fb > 0 && fc > 0) || (fb < 0 && fc < 0))
                {
                    /* Adjust c for it to have a sign opposite to that of b */
                    c = a; fc = fa;
                }
            }
            /* failed! */
            Tol   = Math.Abs(c - b);
            Maxit = -1;
            return(b);
        }