protected override double solveImpl(ISolver1d f, double xAccuracy) { /* The implementation of the algorithm was inspired by Press, Teukolsky, Vetterling, and Flannery, "Numerical Recipes in C", 2nd edition, Cambridge University Press */ double dx, xMid, fMid; // Orient the search so that f>0 lies at root_+dx if (fxMin_ < 0.0) { dx = xMax_-xMin_; root_ = xMin_; } else { dx = xMin_-xMax_; root_ = xMax_; } while (evaluationNumber_ <= maxEvaluations_) { dx /= 2.0; xMid = root_ + dx; fMid = f.value(xMid); evaluationNumber_++; if (fMid <= 0.0) root_ = xMid; if (Math.Abs(dx) < xAccuracy || fMid == 0.0) { return root_; } } throw new ArgumentException("maximum number of function evaluations (" + maxEvaluations_ + ") exceeded"); }
protected override double solveImpl(ISolver1d f, double xAccuracy) { /* The implementation of the algorithm was inspired by Press, Teukolsky, Vetterling, and Flannery, "Numerical Recipes in C", 2nd edition, Cambridge University Press */ double froot, dfroot, dx; froot = f.value(root_); dfroot = f.derivative(root_); if (dfroot == default(double)) throw new ArgumentException("Newton requires function's derivative"); evaluationNumber_++; while (evaluationNumber_<=maxEvaluations_) { dx=froot/dfroot; root_ -= dx; // jumped out of brackets, switch to NewtonSafe if ((xMin_-root_)*(root_-xMax_) < 0.0) { NewtonSafe s = new NewtonSafe(); s.setMaxEvaluations(maxEvaluations_-evaluationNumber_); return s.solve(f, xAccuracy, root_+dx, xMin_, xMax_); } if (Math.Abs(dx) < xAccuracy) return root_; froot = f.value(root_); dfroot = f.derivative(root_); evaluationNumber_++; } throw new ApplicationException("maximum number of function evaluations (" + maxEvaluations_ + ") exceeded"); }
protected override double solveImpl(ISolver1d f, double xAcc) { /* The implementation of the algorithm was inspired by Press, Teukolsky, Vetterling, and Flannery, "Numerical Recipes in C", 2nd edition, Cambridge University Press */ double fxMid, froot, s, xMid, nextRoot; // test on Black-Scholes implied volatility show that // Ridder solver algorithm actually provides an // accuracy 100 times below promised double xAccuracy = xAcc/100.0; // Any highly unlikely value, to simplify logic below root_ = double.MinValue; while (evaluationNumber_ <= maxEvaluations_) { xMid = 0.5*(xMin_ + xMax_); // First of two function evaluations per iteraton fxMid = f.value(xMid); evaluationNumber_++; s = Math.Sqrt(fxMid*fxMid - fxMin_*fxMax_); if (s == 0.0) return root_; // Updating formula nextRoot = xMid + (xMid - xMin_) * ((fxMin_ >= fxMax_ ? 1.0 : -1.0) * fxMid / s); if (Math.Abs(nextRoot-root_) <= xAccuracy) return root_; root_ = nextRoot; // Second of two function evaluations per iteration froot = f.value(root_); evaluationNumber_++; if (froot == 0.0) return root_; // Bookkeeping to keep the root bracketed on next iteration if (sign(fxMid,froot) != fxMid) { xMin_ = xMid; fxMin_ = fxMid; xMax_ = root_; fxMax_ = froot; } else if (sign(fxMin_,froot) != fxMin_) { xMax_ = root_; fxMax_ = froot; } else if (sign(fxMax_,froot) != fxMax_) { xMin_ = root_; fxMin_ = froot; } else { throw new Exception("never get here."); } if (Math.Abs(xMax_-xMin_) <= xAccuracy) return root_; } throw new ArgumentException("maximum number of function evaluations (" + maxEvaluations_ + ") exceeded"); }
/*! This method returns the zero of the function \f$ f \f$, determined with the given accuracy \f$ \epsilon \f$; depending on the particular solver, this might mean that the returned \f$ x \f$ is such that \f$ |f(x)| < \epsilon \f$, or that \f$ |x-\xi| < \epsilon \f$ where \f$ \xi \f$ is the real zero. This method contains a bracketing routine to which an initial guess must be supplied as well as a step used to scan the range of the possible bracketing values. */ public double solve(ISolver1d f, double accuracy, double guess, double step) { if (accuracy <= 0.0) throw new ArgumentException("accuracy (" + accuracy + ") must be positive"); // check whether we really want to use epsilon accuracy = Math.Max(accuracy, Const.QL_EPSILON); const double growthFactor = 1.6; int flipflop = -1; root_ = guess; fxMax_ = f.value(root_); // monotonically crescent bias, as in optionValue(volatility) if (fxMax_ == 0.0) return root_; else if (fxMax_ > 0.0) { xMin_ = enforceBounds_(root_ - step); fxMin_ = f.value(xMin_); xMax_ = root_; } else { xMin_ = root_; fxMin_ = fxMax_; xMax_ = enforceBounds_(root_ + step); fxMax_ = f.value(xMax_); } evaluationNumber_ = 2; while (evaluationNumber_ <= maxEvaluations_) { if (fxMin_ * fxMax_ <= 0.0) { if (fxMin_ == 0.0) return xMin_; if (fxMax_ == 0.0) return xMax_; root_ = (xMax_ + xMin_) / 2.0; return solveImpl(f, accuracy); } if (Math.Abs(fxMin_) < Math.Abs(fxMax_)) { xMin_ = enforceBounds_(xMin_ + growthFactor * (xMin_ - xMax_)); fxMin_ = f.value(xMin_); } else if (Math.Abs(fxMin_) > Math.Abs(fxMax_)) { xMax_ = enforceBounds_(xMax_ + growthFactor * (xMax_ - xMin_)); fxMax_ = f.value(xMax_); } else if (flipflop == -1) { xMin_ = enforceBounds_(xMin_ + growthFactor * (xMin_ - xMax_)); fxMin_ = f.value(xMin_); evaluationNumber_++; flipflop = 1; } else if (flipflop == 1) { xMax_ = enforceBounds_(xMax_ + growthFactor * (xMax_ - xMin_)); fxMax_ = f.value(xMax_); flipflop = -1; } evaluationNumber_++; } throw new ArgumentException("unable to bracket root in " + maxEvaluations_ + " function evaluations (last bracket attempt: " + "f[" + xMin_ + "," + xMax_ + "] " + "-> [" + fxMin_ + "," + fxMax_ + "])"); }
//! safe %Newton 1-D solver /*! \note This solver requires that the passed function object implement a method <tt>Real derivative(Real)</tt>. */ protected override double solveImpl(ISolver1d f, double xAccuracy) { /* The implementation of the algorithm was inspired by Press, Teukolsky, Vetterling, and Flannery, "Numerical Recipes in C", 2nd edition, Cambridge University Press */ double froot, dfroot, dx, dxold; double xh, xl; // Orient the search so that f(xl) < 0 if (fxMin_ < 0.0) { xl=xMin_; xh=xMax_; } else { xh=xMin_; xl=xMax_; } // the "stepsize before last" dxold=xMax_-xMin_; // it was dxold=std::fabs(xMax_-xMin_); in Numerical Recipes // here (xMax_-xMin_ > 0) is verified in the constructor // and the last step dx=dxold; froot = f.value(root_); dfroot = f.derivative(root_); if (dfroot == default(double)) throw new ArgumentException("Newton requires function's derivative"); evaluationNumber_++; while (evaluationNumber_<=maxEvaluations_) { // Bisect if (out of range || not decreasing fast enough) if ((((root_-xh)*dfroot-froot)* ((root_-xl)*dfroot-froot) > 0.0) || (Math.Abs(2.0*froot) > Math.Abs(dxold*dfroot))) { dxold = dx; dx = (xh-xl)/2.0; root_=xl+dx; } else { dxold=dx; dx=froot/dfroot; root_ -= dx; } // Convergence criterion if (Math.Abs(dx) < xAccuracy) return root_; froot = f.value(root_); dfroot = f.derivative(root_); evaluationNumber_++; if (froot < 0.0) xl=root_; else xh=root_; } throw new ApplicationException("maximum number of function evaluations (" + maxEvaluations_ + ") exceeded"); }
/*! This method returns the zero of the function \f$ f \f$, determined with the given accuracy \f$ \epsilon \f$; * depending on the particular solver, this might mean that the returned \f$ x \f$ is such that \f$ |f(x)| < \epsilon * \f$, or that \f$ |x-\xi| < \epsilon \f$ where \f$ \xi \f$ is the real zero. * * An initial guess must be supplied, as well as two values \f$ x_\mathrm{min} \f$ and \f$ x_\mathrm{max} \f$ which * must bracket the zero (i.e., either \f$ f(x_\mathrm{min}) \leq 0 \leq f(x_\mathrm{max}) \f$, or \f$ * f(x_\mathrm{max}) \leq 0 \leq f(x_\mathrm{min}) \f$ must be true). */ public double solve(ISolver1d f, double accuracy, double guess, double xMin, double xMax) { if (accuracy <= 0.0) { throw new ArgumentException("accuracy (" + accuracy + ") must be positive"); } // check whether we really want to use epsilon accuracy = Math.Max(accuracy, Const.QL_Epsilon); xMin_ = xMin; xMax_ = xMax; if (!(xMin_ < xMax_)) { throw new ArgumentException("invalid range: xMin_ (" + xMin_ + ") >= xMax_ (" + xMax_ + ")"); } if (!(!lowerBoundEnforced_ || xMin_ >= lowerBound_)) { throw new ArgumentException("xMin_ (" + xMin_ + ") < enforced low bound (" + lowerBound_ + ")"); } if (!(!upperBoundEnforced_ || xMax_ <= upperBound_)) { throw new ArgumentException("xMax_ (" + xMax_ + ") > enforced hi bound (" + upperBound_ + ")"); } fxMin_ = f.value(xMin_); if (fxMin_ == 0.0) { return(xMin_); } fxMax_ = f.value(xMax_); if (fxMax_ == 0.0) { return(xMax_); } evaluationNumber_ = 2; if (!(fxMin_ * fxMax_ < 0.0)) { throw new ArgumentException("root not bracketed: f[" + xMin_ + "," + xMax_ + "] -> [" + fxMin_ + "," + fxMax_ + "]"); } if (!(guess > xMin_)) { throw new ArgumentException("guess (" + guess + ") < xMin_ (" + xMin_ + ")"); } if (!(guess < xMax_)) { throw new ArgumentException("guess (" + guess + ") > xMax_ (" + xMax_ + ")"); } root_ = guess; return(solveImpl(f, accuracy)); }
protected override double solveImpl(ISolver1d f, double xAccuracy) { /* The implementation of the algorithm was inspired by * Press, Teukolsky, Vetterling, and Flannery, * "Numerical Recipes in C", 2nd edition, * Cambridge University Press */ double fl, fh, xl, xh, dx, del, froot; // Identify the limits so that xl corresponds to the low side if (fxMin_ < 0.0) { xl = xMin_; fl = fxMin_; xh = xMax_; fh = fxMax_; } else { xl = xMax_; fl = fxMax_; xh = xMin_; fh = fxMin_; } dx = xh - xl; while (evaluationNumber_ <= maxEvaluations_) { // Increment with respect to latest value root_ = xl + dx * fl / (fl - fh); froot = f.value(root_); evaluationNumber_++; if (froot < 0.0) // Replace appropriate limit { del = xl - root_; xl = root_; fl = froot; } else { del = xh - root_; xh = root_; fh = froot; } dx = xh - xl; // Convergence criterion if (Math.Abs(del) < xAccuracy || Utils.close(froot, 0.0)) { return(root_); } } Utils.QL_FAIL("maximum number of function evaluations (" + maxEvaluations_ + ") exceeded", QLNetExceptionEnum.MaxNumberFuncEvalExceeded); return(0); }
protected override double solveImpl(ISolver1d f, double xAccuracy) { // Orient the search so that f(xl) < 0 double xh, xl; if (fxMin_ < 0.0) { xl = xMin_; xh = xMax_; } else { xh = xMin_; xl = xMax_; } double froot = f.value(root_); ++evaluationNumber_; // first order finite difference derivative double dfroot = xMax_-root_ < root_-xMin_ ? (fxMax_-froot)/(xMax_-root_) : (fxMin_-froot)/(xMin_-root_) ; // xMax_-xMin_>0 is verified in the constructor double dx = xMax_-xMin_; while (evaluationNumber_<=maxEvaluations_) { double frootold = froot; double rootold = root_; double dxold = dx; // Bisect if (out of range || not decreasing fast enough) if ((((root_-xh)*dfroot-froot)* ((root_-xl)*dfroot-froot) > 0.0) || (Math.Abs(2.0*froot) > Math.Abs(dxold*dfroot))) { dx = (xh-xl)/2.0; root_ = xl+dx; } else { // Newton dx = froot/dfroot; root_ -= dx; } // Convergence criterion if (Math.Abs(dx) < xAccuracy) return root_; froot = f.value(root_); ++evaluationNumber_; dfroot = (frootold-froot)/(rootold-root_); if (froot < 0.0) xl=root_; else xh=root_; } throw new ArgumentException( "maximum number of function evaluations (" + maxEvaluations_ + ") exceeded" ); }
protected override double solveImpl(ISolver1d f, double xAccuracy) { /* The implementation of the algorithm was inspired by Press, Teukolsky, Vetterling, and Flannery, "Numerical Recipes in C", 2nd edition, Cambridge University Press */ double fl, fh, xl, xh, dx, del, froot; // Identify the limits so that xl corresponds to the low side if (fxMin_ < 0.0) { xl = xMin_; fl = fxMin_; xh = xMax_; fh = fxMax_; } else { xl = xMax_; fl = fxMax_; xh = xMin_; fh = fxMin_; } dx = xh - xl ; while (evaluationNumber_ <= maxEvaluations_) { // Increment with respect to latest value root_ = xl + dx*fl/(fl-fh); froot = f.value(root_); evaluationNumber_++; if (froot < 0.0) { // Replace appropriate limit del = xl - root_; xl = root_; fl = froot; } else { del = xh - root_; xh = root_; fh = froot; } dx = xh - xl; // Convergence criterion if (Math.Abs(del) < xAccuracy || froot == 0.0) { return root_; } } throw new ArgumentException("maximum number of function evaluations (" + maxEvaluations_ + ") exceeded"); }
protected override double solveImpl(ISolver1d f, double xAccuracy) { /* The implementation of the algorithm was inspired by * Press, Teukolsky, Vetterling, and Flannery, * "Numerical Recipes in C", 2nd edition, Cambridge * University Press */ double fl, froot, dx, xl; // Pick the bound with the smaller function value // as the most recent guess if (Math.Abs(fxMin_) < Math.Abs(fxMax_)) { root_ = xMin_; froot = fxMin_; xl = xMax_; fl = fxMax_; } else { root_ = xMax_; froot = fxMax_; xl = xMin_; fl = fxMin_; } while (evaluationNumber_ <= maxEvaluations_) { dx = (xl - root_) * froot / (froot - fl); xl = root_; fl = froot; root_ += dx; froot = f.value(root_); ++evaluationNumber_; if (Math.Abs(dx) < xAccuracy || Utils.close(froot, 0.0)) { return(root_); } } Utils.QL_FAIL("maximum number of function evaluations (" + maxEvaluations_ + ") exceeded", QLNetExceptionEnum.MaxNumberFuncEvalExceeded); return(0); }
protected override double solveImpl(ISolver1d f, double xAccuracy) { /* The implementation of the algorithm was inspired by * Press, Teukolsky, Vetterling, and Flannery, * "Numerical Recipes in C", 2nd edition, Cambridge * University Press */ double dx, xMid, fMid; // Orient the search so that f>0 lies at root_+dx if (fxMin_ < 0.0) { dx = xMax_ - xMin_; root_ = xMin_; } else { dx = xMin_ - xMax_; root_ = xMax_; } while (evaluationNumber_ <= maxEvaluations_) { dx /= 2.0; xMid = root_ + dx; fMid = f.value(xMid); evaluationNumber_++; if (fMid <= 0.0) { root_ = xMid; } if (Math.Abs(dx) < xAccuracy || Utils.close(fMid, 0.0)) { return(root_); } } Utils.QL_FAIL("maximum number of function evaluations (" + maxEvaluations_ + ") exceeded", QLNetExceptionEnum.MaxNumberFuncEvalExceeded); return(0); }
protected override double solveImpl(ISolver1d f, double xAccuracy) { /* The implementation of the algorithm was inspired by Press, Teukolsky, Vetterling, and Flannery, * "Numerical Recipes in C", 2nd edition, Cambridge University Press */ double froot, dfroot, dx; froot = f.value(root_); dfroot = f.derivative(root_); if (dfroot.IsEqual(default(double))) { throw new ArgumentException("Newton requires function's derivative"); } ++evaluationNumber_; while (evaluationNumber_ <= maxEvaluations_) { dx = froot / dfroot; root_ -= dx; // jumped out of brackets, switch to NewtonSafe if ((xMin_ - root_) * (root_ - xMax_) < 0.0) { NewtonSafe s = new NewtonSafe(); s.setMaxEvaluations(maxEvaluations_ - evaluationNumber_); return(s.solve(f, xAccuracy, root_ + dx, xMin_, xMax_)); } if (Math.Abs(dx) < xAccuracy) { return(root_); } froot = f.value(root_); dfroot = f.derivative(root_); evaluationNumber_++; } Utils.QL_FAIL("maximum number of function evaluations (" + maxEvaluations_ + ") exceeded", QLNetExceptionEnum.MaxNumberFuncEvalExceeded); return(0); }
/*! This method returns the zero of the function \f$ f \f$, determined with the given accuracy \f$ \epsilon \f$ * depending on the particular solver, this might mean that the returned \f$ x \f$ is such that \f$ |f(x)| < \epsilon * \f$, or that \f$ |x-\xi| < \epsilon \f$ where \f$ \xi \f$ is the real zero. * * An initial guess must be supplied, as well as two values \f$ x_\mathrm{min} \f$ and \f$ x_\mathrm{max} \f$ which * must bracket the zero (i.e., either \f$ f(x_\mathrm{min}) \leq 0 \leq f(x_\mathrm{max}) \f$, or \f$ * f(x_\mathrm{max}) \leq 0 \leq f(x_\mathrm{min}) \f$ must be true). */ public double solve(ISolver1d f, double accuracy, double guess, double xMin, double xMax) { Utils.QL_REQUIRE(accuracy > 0.0, () => "accuracy (" + accuracy + ") must be positive"); // check whether we really want to use epsilon accuracy = Math.Max(accuracy, Const.QL_EPSILON); xMin_ = xMin; xMax_ = xMax; Utils.QL_REQUIRE(xMin_ < xMax_, () => "invalid range: xMin_ (" + xMin_ + ") >= xMax_ (" + xMax_ + ")"); Utils.QL_REQUIRE(!lowerBoundEnforced_ || xMin_ >= lowerBound_, () => "xMin_ (" + xMin_ + ") < enforced low bound (" + lowerBound_ + ")"); Utils.QL_REQUIRE(!upperBoundEnforced_ || xMax_ <= upperBound_, () => "xMax_ (" + xMax_ + ") > enforced hi bound (" + upperBound_ + ")"); fxMin_ = f.value(xMin_); if (Utils.close(fxMin_, 0.0)) { return(xMin_); } fxMax_ = f.value(xMax_); if (Utils.close(fxMax_, 0.0)) { return(xMax_); } evaluationNumber_ = 2; Utils.QL_REQUIRE(fxMin_ * fxMax_ < 0.0, () => "root not bracketed: f[" + xMin_ + "," + xMax_ + "] -> [" + fxMin_ + "," + fxMax_ + "]"); Utils.QL_REQUIRE(guess > xMin_, () => "guess (" + guess + ") < xMin_ (" + xMin_ + ")"); Utils.QL_REQUIRE(guess < xMax_, () => "guess (" + guess + ") > xMax_ (" + xMax_ + ")"); root_ = guess; return(solveImpl(f, accuracy)); }
protected override double solveImpl(ISolver1d f, double xAccuracy) { /* The implementation of the algorithm was inspired by Press, Teukolsky, Vetterling, and Flannery, "Numerical Recipes in C", 2nd edition, Cambridge University Press */ double fl, froot, dx, xl; // Pick the bound with the smaller function value // as the most recent guess if (Math.Abs(fxMin_) < Math.Abs(fxMax_)) { root_ = xMin_; froot = fxMin_; xl = xMax_; fl = fxMax_; } else { root_ = xMax_; froot = fxMax_; xl = xMin_; fl = fxMin_; } while (evaluationNumber_ <= maxEvaluations_) { dx = (xl-root_)*froot/(froot-fl); xl = root_; fl = froot; root_ += dx; froot = f.value(root_); evaluationNumber_++; if (Math.Abs(dx) < xAccuracy || froot == 0.0) return root_; } throw new ArgumentException("maximum number of function evaluations (" + maxEvaluations_ + ") exceeded"); }
//! safe %Newton 1-D solver /*! \note This solver requires that the passed function object * implement a method <tt>Real derivative(Real)</tt>. */ protected override double solveImpl(ISolver1d f, double xAccuracy) { /* The implementation of the algorithm was inspired by Press, Teukolsky, Vetterling, and Flannery, * "Numerical Recipes in C", 2nd edition, Cambridge University Press */ double froot, dfroot, dx, dxold; double xh, xl; // Orient the search so that f(xl) < 0 if (fxMin_ < 0.0) { xl = xMin_; xh = xMax_; } else { xh = xMin_; xl = xMax_; } // the "stepsize before last" dxold = xMax_ - xMin_; // it was dxold=std::fabs(xMax_-xMin_); in Numerical Recipes // here (xMax_-xMin_ > 0) is verified in the constructor // and the last step dx = dxold; froot = f.value(root_); dfroot = f.derivative(root_); if (dfroot == default(double)) { throw new ArgumentException("Newton requires function's derivative"); } ++evaluationNumber_; while (evaluationNumber_ <= maxEvaluations_) { // Bisect if (out of range || not decreasing fast enough) if ((((root_ - xh) * dfroot - froot) * ((root_ - xl) * dfroot - froot) > 0.0) || (Math.Abs(2.0 * froot) > Math.Abs(dxold * dfroot))) { dxold = dx; dx = (xh - xl) / 2.0; root_ = xl + dx; } else { dxold = dx; dx = froot / dfroot; root_ -= dx; } // Convergence criterion if (Math.Abs(dx) < xAccuracy) { return(root_); } froot = f.value(root_); dfroot = f.derivative(root_); evaluationNumber_++; if (froot < 0.0) { xl = root_; } else { xh = root_; } } throw new ApplicationException("maximum number of function evaluations (" + maxEvaluations_ + ") exceeded"); }
protected abstract double solveImpl(ISolver1d f, double xAccuracy);
/*! This method returns the zero of the function \f$ f \f$, determined with the given accuracy \f$ \epsilon \f$; depending on the particular solver, this might mean that the returned \f$ x \f$ is such that \f$ |f(x)| < \epsilon \f$, or that \f$ |x-\xi| < \epsilon \f$ where \f$ \xi \f$ is the real zero. An initial guess must be supplied, as well as two values \f$ x_\mathrm{min} \f$ and \f$ x_\mathrm{max} \f$ which must bracket the zero (i.e., either \f$ f(x_\mathrm{min}) \leq 0 \leq f(x_\mathrm{max}) \f$, or \f$ f(x_\mathrm{max}) \leq 0 \leq f(x_\mathrm{min}) \f$ must be true). */ public double solve(ISolver1d f, double accuracy, double guess, double xMin, double xMax) { if (accuracy <= 0.0) throw new ArgumentException("accuracy (" + accuracy + ") must be positive"); // check whether we really want to use epsilon accuracy = Math.Max(accuracy, Const.QL_Epsilon); xMin_ = xMin; xMax_ = xMax; if (!(xMin_ < xMax_)) throw new ArgumentException("invalid range: xMin_ (" + xMin_ + ") >= xMax_ (" + xMax_ + ")"); if (!(!lowerBoundEnforced_ || xMin_ >= lowerBound_)) throw new ArgumentException("xMin_ (" + xMin_ + ") < enforced low bound (" + lowerBound_ + ")"); if (!(!upperBoundEnforced_ || xMax_ <= upperBound_)) throw new ArgumentException("xMax_ (" + xMax_ + ") > enforced hi bound (" + upperBound_ + ")"); fxMin_ = f.value(xMin_); if (fxMin_ == 0.0) return xMin_; fxMax_ = f.value(xMax_); if (fxMax_ == 0.0) return xMax_; evaluationNumber_ = 2; if (!(fxMin_ * fxMax_ < 0.0)) throw new ArgumentException("root not bracketed: f[" + xMin_ + "," + xMax_ + "] -> [" + fxMin_ + "," + fxMax_ + "]"); if (!(guess > xMin_)) throw new ArgumentException("guess (" + guess + ") < xMin_ (" + xMin_ + ")"); if (!(guess < xMax_)) throw new ArgumentException("guess (" + guess + ") > xMax_ (" + xMax_ + ")"); root_ = guess; return solveImpl(f, accuracy); }
/*! This method returns the zero of the function \f$ f \f$, determined with the given accuracy \f$ \epsilon \f$ * depending on the particular solver, this might mean that the returned \f$ x \f$ is such that \f$ |f(x)| < \epsilon * \f$, or that \f$ |x-\xi| < \epsilon \f$ where \f$ \xi \f$ is the real zero. * * This method contains a bracketing routine to which an initial guess must be supplied as well as a step used to * scan the range of the possible bracketing values. */ public double solve(ISolver1d f, double accuracy, double guess, double step) { Utils.QL_REQUIRE(accuracy > 0.0, () => "accuracy (" + accuracy + ") must be positive"); // check whether we really want to use epsilon accuracy = Math.Max(accuracy, Const.QL_EPSILON); const double growthFactor = 1.6; int flipflop = -1; root_ = guess; fxMax_ = f.value(root_); // monotonically crescent bias, as in optionValue(volatility) if (Utils.close(fxMax_, 0.0)) { return(root_); } else if (fxMax_ > 0.0) { xMin_ = enforceBounds_(root_ - step); fxMin_ = f.value(xMin_); xMax_ = root_; } else { xMin_ = root_; fxMin_ = fxMax_; xMax_ = enforceBounds_(root_ + step); fxMax_ = f.value(xMax_); } evaluationNumber_ = 2; while (evaluationNumber_ <= maxEvaluations_) { if (fxMin_ * fxMax_ <= 0.0) { if (Utils.close(fxMin_, 0.0)) { return(xMin_); } if (Utils.close(fxMax_, 0.0)) { return(xMax_); } root_ = (xMax_ + xMin_) / 2.0; return(solveImpl(f, accuracy)); } if (Math.Abs(fxMin_) < Math.Abs(fxMax_)) { xMin_ = enforceBounds_(xMin_ + growthFactor * (xMin_ - xMax_)); fxMin_ = f.value(xMin_); } else if (Math.Abs(fxMin_) > Math.Abs(fxMax_)) { xMax_ = enforceBounds_(xMax_ + growthFactor * (xMax_ - xMin_)); fxMax_ = f.value(xMax_); } else if (flipflop == -1) { xMin_ = enforceBounds_(xMin_ + growthFactor * (xMin_ - xMax_)); fxMin_ = f.value(xMin_); evaluationNumber_++; flipflop = 1; } else if (flipflop == 1) { xMax_ = enforceBounds_(xMax_ + growthFactor * (xMax_ - xMin_)); fxMax_ = f.value(xMax_); flipflop = -1; } evaluationNumber_++; } Utils.QL_FAIL("unable to bracket root in " + maxEvaluations_ + " function evaluations (last bracket attempt: " + "f[" + xMin_ + "," + xMax_ + "] " + "-> [" + fxMin_ + "," + fxMax_ + "])"); return(0); }
protected override double solveImpl(ISolver1d f, double xAcc) { /* The implementation of the algorithm was inspired by * Press, Teukolsky, Vetterling, and Flannery, * "Numerical Recipes in C", 2nd edition, Cambridge * University Press */ double fxMid, froot, s, xMid, nextRoot; // test on Black-Scholes implied volatility show that // Ridder solver algorithm actually provides an // accuracy 100 times below promised double xAccuracy = xAcc / 100.0; // Any highly unlikely value, to simplify logic below root_ = double.MinValue; while (evaluationNumber_ <= maxEvaluations_) { xMid = 0.5 * (xMin_ + xMax_); // First of two function evaluations per iteraton fxMid = f.value(xMid); ++evaluationNumber_; s = Math.Sqrt(fxMid * fxMid - fxMin_ * fxMax_); if (Utils.close(s, 0.0)) { return(root_); } // Updating formula nextRoot = xMid + (xMid - xMin_) * ((fxMin_ >= fxMax_ ? 1.0 : -1.0) * fxMid / s); if (Math.Abs(nextRoot - root_) <= xAccuracy) { return(root_); } root_ = nextRoot; // Second of two function evaluations per iteration froot = f.value(root_); ++evaluationNumber_; if (Utils.close(froot, 0.0)) { return(root_); } // Bookkeeping to keep the root bracketed on next iteration if (sign(fxMid, froot).IsNotEqual(fxMid)) { xMin_ = xMid; fxMin_ = fxMid; xMax_ = root_; fxMax_ = froot; } else if (sign(fxMin_, froot).IsNotEqual(fxMin_)) { xMax_ = root_; fxMax_ = froot; } else if (sign(fxMax_, froot).IsNotEqual(fxMax_)) { xMin_ = root_; fxMin_ = froot; } else { Utils.QL_FAIL("never get here."); } if (Math.Abs(xMax_ - xMin_) <= xAccuracy) { return(root_); } } throw new ArgumentException("maximum number of function evaluations (" + maxEvaluations_ + ") exceeded"); }
protected override double solveImpl(ISolver1d f, double xAccuracy) { /* The implementation of the algorithm was inspired by Press, Teukolsky, Vetterling, and Flannery, "Numerical Recipes in C", 2nd edition, Cambridge University Press */ double min1, min2; double froot, p, q, r, s, xAcc1, xMid; // dummy assignements to avoid compiler warning double d = 0.0, e = 0.0; root_ = xMax_; froot = fxMax_; while (evaluationNumber_ <= maxEvaluations_) { if ((froot > 0.0 && fxMax_ > 0.0) || (froot < 0.0 && fxMax_ < 0.0)) { // Rename xMin_, root_, xMax_ and adjust bounds xMax_ = xMin_; fxMax_ = fxMin_; e = d = root_ - xMin_; } if (Math.Abs(fxMax_) < Math.Abs(froot)) { xMin_ = root_; root_ = xMax_; xMax_ = xMin_; fxMin_ = froot; froot = fxMax_; fxMax_ = fxMin_; } // Convergence check xAcc1 = 2.0 * Const.QL_EPSILON * Math.Abs(root_) + 0.5 * xAccuracy; xMid = (xMax_ - root_) / 2.0; if (Math.Abs(xMid) <= xAcc1 || froot == 0.0) return root_; if (Math.Abs(e) >= xAcc1 && Math.Abs(fxMin_) > Math.Abs(froot)) { // Attempt inverse quadratic interpolation s = froot / fxMin_; if (xMin_ == xMax_) { p = 2.0 * xMid * s; q = 1.0 - s; } else { q = fxMin_ / fxMax_; r = froot / fxMax_; p = s * (2.0 * xMid * q * (q - r) - (root_ - xMin_) * (r - 1.0)); q = (q - 1.0) * (r - 1.0) * (s - 1.0); } if (p > 0.0) q = -q; // Check whether in bounds p = Math.Abs(p); min1 = 3.0 * xMid * q - Math.Abs(xAcc1 * q); min2 = Math.Abs(e * q); if (2.0 * p < (min1 < min2 ? min1 : min2)) { e = d; // Accept interpolation d = p / q; } else { d = xMid; // Interpolation failed, use bisection e = d; } } else { // Bounds decreasing too slowly, use bisection d = xMid; e = d; } xMin_ = root_; fxMin_ = froot; if (Math.Abs(d) > xAcc1) root_ += d; else root_ += Math.Abs(xAcc1) * Math.Sign(xMid); froot = f.value(root_); evaluationNumber_++; } throw new ArgumentException("maximum number of function evaluations (" + maxEvaluations_ + ") exceeded"); }
protected override double solveImpl(ISolver1d f, double xAccuracy) { // Orient the search so that f(xl) < 0 double xh, xl; if (fxMin_ < 0.0) { xl = xMin_; xh = xMax_; } else { xh = xMin_; xl = xMax_; } double froot = f.value(root_); ++evaluationNumber_; // first order finite difference derivative double dfroot = xMax_ - root_ < root_ - xMin_ ? (fxMax_ - froot) / (xMax_ - root_) : (fxMin_ - froot) / (xMin_ - root_); // xMax_-xMin_>0 is verified in the constructor double dx = xMax_ - xMin_; while (evaluationNumber_ <= maxEvaluations_) { double frootold = froot; double rootold = root_; double dxold = dx; // Bisect if (out of range || not decreasing fast enough) if ((((root_ - xh) * dfroot - froot) * ((root_ - xl) * dfroot - froot) > 0.0) || (Math.Abs(2.0 * froot) > Math.Abs(dxold * dfroot))) { dx = (xh - xl) / 2.0; root_ = xl + dx; } else // Newton { dx = froot / dfroot; root_ -= dx; } // Convergence criterion if (Math.Abs(dx) < xAccuracy) { return(root_); } froot = f.value(root_); ++evaluationNumber_; dfroot = (frootold - froot) / (rootold - root_); if (froot < 0.0) { xl = root_; } else { xh = root_; } } throw new ArgumentException("maximum number of function evaluations (" + maxEvaluations_ + ") exceeded"); }
protected override double solveImpl(ISolver1d f, double xAccuracy) { /* The implementation of the algorithm was inspired by Press, Teukolsky, Vetterling, and Flannery, * "Numerical Recipes in C", 2nd edition, Cambridge University Press */ double min1, min2; double froot, p, q, r, s, xAcc1, xMid; // dummy assignements to avoid compiler warning double d = 0.0, e = 0.0; root_ = xMax_; froot = fxMax_; while (evaluationNumber_ <= maxEvaluations_) { if ((froot > 0.0 && fxMax_ > 0.0) || (froot < 0.0 && fxMax_ < 0.0)) { // Rename xMin_, root_, xMax_ and adjust bounds xMax_ = xMin_; fxMax_ = fxMin_; e = d = root_ - xMin_; } if (Math.Abs(fxMax_) < Math.Abs(froot)) { xMin_ = root_; root_ = xMax_; xMax_ = xMin_; fxMin_ = froot; froot = fxMax_; fxMax_ = fxMin_; } // Convergence check xAcc1 = 2.0 * Const.QL_Epsilon * Math.Abs(root_) + 0.5 * xAccuracy; xMid = (xMax_ - root_) / 2.0; if (Math.Abs(xMid) <= xAcc1 || froot == 0.0) { return(root_); } if (Math.Abs(e) >= xAcc1 && Math.Abs(fxMin_) > Math.Abs(froot)) { // Attempt inverse quadratic interpolation s = froot / fxMin_; if (xMin_ == xMax_) { p = 2.0 * xMid * s; q = 1.0 - s; } else { q = fxMin_ / fxMax_; r = froot / fxMax_; p = s * (2.0 * xMid * q * (q - r) - (root_ - xMin_) * (r - 1.0)); q = (q - 1.0) * (r - 1.0) * (s - 1.0); } if (p > 0.0) { q = -q; // Check whether in bounds } p = Math.Abs(p); min1 = 3.0 * xMid * q - Math.Abs(xAcc1 * q); min2 = Math.Abs(e * q); if (2.0 * p < (min1 < min2 ? min1 : min2)) { e = d; // Accept interpolation d = p / q; } else { d = xMid; // Interpolation failed, use bisection e = d; } } else { // Bounds decreasing too slowly, use bisection d = xMid; e = d; } xMin_ = root_; fxMin_ = froot; if (Math.Abs(d) > xAcc1) { root_ += d; } else { root_ += Math.Abs(xAcc1) * Math.Sign(xMid); } froot = f.value(root_); evaluationNumber_++; } throw new ArgumentException("maximum number of function evaluations (" + maxEvaluations_ + ") exceeded"); }