/*! 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 || 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 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 || Utils.close(froot, 0.0)) { return(root_); } if (Math.Abs(e) >= xAcc1 && Math.Abs(fxMin_) > Math.Abs(froot)) { // Attempt inverse quadratic interpolation s = froot / fxMin_; if (Utils.close(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_++; } 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. * * 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_ + "])", QLNetExceptionEnum.RootNotBracketException); 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_); } } 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_; } } Utils.QL_FAIL("maximum number of function evaluations (" + maxEvaluations_ + ") exceeded", QLNetExceptionEnum.MaxNumberFuncEvalExceeded); return(0); }
//! 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.IsEqual(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_; } } Utils.QL_FAIL("maximum number of function evaluations (" + maxEvaluations_ + ") exceeded", QLNetExceptionEnum.MaxNumberFuncEvalExceeded); return(0); }