/** {@inheritDoc} */ public double solve(final UnivariateRealFunction f, double min, double max) throws MaxIterationsExceededException, FunctionEvaluationException { clearResult(); verifyInterval(min, max); double m; double fm; double fmin; int i = 0; while (i < maximalIterationCount) { m = UnivariateRealSolverUtils.midpoint(min, max); fmin = f.value(min); fm = f.value(m); if (fm * fmin > 0.0) { // max and m bracket the root. min = m; } else { // min and m bracket the root. max = m; } if (Math.abs(max - min) <= absoluteAccuracy) { m = UnivariateRealSolverUtils.midpoint(min, max); setResult(m, i); return m; } ++i; } throw new MaxIterationsExceededException(maximalIterationCount); }
/** * For this distribution, X, this method returns the critical point x, such that P(X < x) = * <code>p</code>. * * @param p the desired probability * @return x, such that P(X < x) = <code>p</code> * @throws MathException if the inverse cumulative probability can not be computed due to * convergence or other numerical errors. * @throws IllegalArgumentException if <code>p</code> is not a valid probability. */ public double inverseCumulativeProbability(final double p) throws MathException { if (p < 0.0 || p > 1.0) { throw MathRuntimeException.createIllegalArgumentException( "{0} out of [{1}, {2}] range", p, 0.0, 1.0); } // by default, do simple root finding using bracketing and default solver. // subclasses can overide if there is a better method. UnivariateRealFunction rootFindingFunction = new UnivariateRealFunction() { private static final long serialVersionUID = 1043729002768873023L; public double value(double x) throws FunctionEvaluationException { try { return cumulativeProbability(x) - p; } catch (MathException ex) { throw new FunctionEvaluationException(ex, x, ex.getPattern(), ex.getArguments()); } } }; // Try to bracket root, test domain endoints if this fails double lowerBound = getDomainLowerBound(p); double upperBound = getDomainUpperBound(p); double[] bracket = null; try { bracket = UnivariateRealSolverUtils.bracket( rootFindingFunction, getInitialDomain(p), lowerBound, upperBound); } catch (ConvergenceException ex) { /* * Check domain endpoints to see if one gives value that is within * the default solver's defaultAbsoluteAccuracy of 0 (will be the * case if density has bounded support and p is 0 or 1). * * TODO: expose the default solver, defaultAbsoluteAccuracy as * a constant. */ if (Math.abs(rootFindingFunction.value(lowerBound)) < 1E-6) { return lowerBound; } if (Math.abs(rootFindingFunction.value(upperBound)) < 1E-6) { return upperBound; } // Failed bracket convergence was not because of corner solution throw new MathException(ex); } // find root double root = UnivariateRealSolverUtils.solve(rootFindingFunction, bracket[0], bracket[1]); return root; }