| Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||||||
| RiddersSolver |
|
| 8.666666666666666;8.667 |
| 1 | /* |
|
| 2 | * Copyright 2005 The Apache Software Foundation. |
|
| 3 | * |
|
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
|
| 5 | * you may not use this file except in compliance with the License. |
|
| 6 | * You may obtain a copy of the License at |
|
| 7 | * |
|
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
|
| 9 | * |
|
| 10 | * Unless required by applicable law or agreed to in writing, software |
|
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
|
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
| 13 | * See the License for the specific language governing permissions and |
|
| 14 | * limitations under the License. |
|
| 15 | */ |
|
| 16 | package org.apache.commons.math.analysis; |
|
| 17 | ||
| 18 | import org.apache.commons.math.ConvergenceException; |
|
| 19 | import org.apache.commons.math.FunctionEvaluationException; |
|
| 20 | import org.apache.commons.math.util.MathUtils; |
|
| 21 | ||
| 22 | /** |
|
| 23 | * Implements the <a href="http://mathworld.wolfram.com/RiddersMethod.html"> |
|
| 24 | * Ridders' Method</a> for root finding of real univariate functions. For |
|
| 25 | * reference, see C. Ridders, <i>A new algorithm for computing a single root |
|
| 26 | * of a real continuous function </i>, IEEE Transactions on Circuits and |
|
| 27 | * Systems, 26 (1979), 979 - 980. |
|
| 28 | * <p> |
|
| 29 | * The function should be continuous but not necessarily smooth. |
|
| 30 | * |
|
| 31 | * @version $Revision$ $Date$ |
|
| 32 | */ |
|
| 33 | public class RiddersSolver extends UnivariateRealSolverImpl { |
|
| 34 | ||
| 35 | /** serializable version identifier */ |
|
| 36 | static final long serialVersionUID = -4703139035737911735L; |
|
| 37 | ||
| 38 | /** |
|
| 39 | * Construct a solver for the given function. |
|
| 40 | * |
|
| 41 | * @param f function to solve |
|
| 42 | */ |
|
| 43 | public RiddersSolver(UnivariateRealFunction f) { |
|
| 44 | 8 | super(f, 100, 1E-6); |
| 45 | 8 | } |
| 46 | ||
| 47 | /** |
|
| 48 | * Find a root in the given interval with initial value. |
|
| 49 | * <p> |
|
| 50 | * Requires bracketing condition. |
|
| 51 | * |
|
| 52 | * @param min the lower bound for the interval |
|
| 53 | * @param max the upper bound for the interval |
|
| 54 | * @param initial the start value to use |
|
| 55 | * @return the point at which the function value is zero |
|
| 56 | * @throws ConvergenceException if the maximum iteration count is exceeded |
|
| 57 | * or the solver detects convergence problems otherwise |
|
| 58 | * @throws FunctionEvaluationException if an error occurs evaluating the |
|
| 59 | * function |
|
| 60 | * @throws IllegalArgumentException if any parameters are invalid |
|
| 61 | */ |
|
| 62 | public double solve(double min, double max, double initial) throws |
|
| 63 | ConvergenceException, FunctionEvaluationException { |
|
| 64 | ||
| 65 | // check for zeros before verifying bracketing |
|
| 66 | 0 | if (f.value(min) == 0.0) { return min; } |
| 67 | 0 | if (f.value(max) == 0.0) { return max; } |
| 68 | 0 | if (f.value(initial) == 0.0) { return initial; } |
| 69 | ||
| 70 | 0 | verifyBracketing(min, max, f); |
| 71 | 0 | verifySequence(min, initial, max); |
| 72 | 0 | if (isBracketing(min, initial, f)) { |
| 73 | 0 | return solve(min, initial); |
| 74 | } else { |
|
| 75 | 0 | return solve(initial, max); |
| 76 | } |
|
| 77 | } |
|
| 78 | ||
| 79 | /** |
|
| 80 | * Find a root in the given interval. |
|
| 81 | * <p> |
|
| 82 | * Requires bracketing condition. |
|
| 83 | * |
|
| 84 | * @param min the lower bound for the interval |
|
| 85 | * @param max the upper bound for the interval |
|
| 86 | * @return the point at which the function value is zero |
|
| 87 | * @throws ConvergenceException if the maximum iteration count is exceeded |
|
| 88 | * or the solver detects convergence problems otherwise |
|
| 89 | * @throws FunctionEvaluationException if an error occurs evaluating the |
|
| 90 | * function |
|
| 91 | * @throws IllegalArgumentException if any parameters are invalid |
|
| 92 | */ |
|
| 93 | public double solve(double min, double max) throws ConvergenceException, |
|
| 94 | FunctionEvaluationException { |
|
| 95 | ||
| 96 | // [x1, x2] is the bracketing interval in each iteration |
|
| 97 | // x3 is the midpoint of [x1, x2] |
|
| 98 | // x is the new root approximation and an endpoint of the new interval |
|
| 99 | double x1, x2, x3, x, oldx, y1, y2, y3, y, delta, correction, tolerance; |
|
| 100 | ||
| 101 | 20 | x1 = min; y1 = f.value(x1); |
| 102 | 20 | x2 = max; y2 = f.value(x2); |
| 103 | ||
| 104 | // check for zeros before verifying bracketing |
|
| 105 | 20 | if (y1 == 0.0) { return min; } |
| 106 | 20 | if (y2 == 0.0) { return max; } |
| 107 | 20 | verifyBracketing(min, max, f); |
| 108 | ||
| 109 | 16 | int i = 1; |
| 110 | 16 | oldx = Double.POSITIVE_INFINITY; |
| 111 | 82 | while (i <= maximalIterationCount) { |
| 112 | // calculate the new root approximation |
|
| 113 | 82 | x3 = 0.5 * (x1 + x2); |
| 114 | 82 | y3 = f.value(x3); |
| 115 | 82 | if (Math.abs(y3) <= functionValueAccuracy) { |
| 116 | 0 | setResult(x3, i); |
| 117 | 0 | return result; |
| 118 | } |
|
| 119 | 82 | delta = 1 - (y1 * y2) / (y3 * y3); // delta > 1 due to bracketing |
| 120 | 82 | correction = (MathUtils.sign(y2) * MathUtils.sign(y3)) * |
| 121 | (x3 - x1) / Math.sqrt(delta); |
|
| 122 | 82 | x = x3 - correction; // correction != 0 |
| 123 | 82 | y = f.value(x); |
| 124 | ||
| 125 | // check for convergence |
|
| 126 | 82 | tolerance = Math.max(relativeAccuracy * Math.abs(x), absoluteAccuracy); |
| 127 | 82 | if (Math.abs(x - oldx) <= tolerance) { |
| 128 | 16 | setResult(x, i); |
| 129 | 16 | return result; |
| 130 | } |
|
| 131 | 66 | if (Math.abs(y) <= functionValueAccuracy) { |
| 132 | 0 | setResult(x, i); |
| 133 | 0 | return result; |
| 134 | } |
|
| 135 | ||
| 136 | // prepare the new interval for next iteration |
|
| 137 | // Ridders' method guarantees x1 < x < x2 |
|
| 138 | 66 | if (correction > 0.0) { // x1 < x < x3 |
| 139 | 42 | if (MathUtils.sign(y1) + MathUtils.sign(y) == 0.0) { |
| 140 | 18 | x2 = x; y2 = y; |
| 141 | } else { |
|
| 142 | 24 | x1 = x; x2 = x3; |
| 143 | 24 | y1 = y; y2 = y3; |
| 144 | } |
|
| 145 | } else { // x3 < x < x2 |
|
| 146 | 24 | if (MathUtils.sign(y2) + MathUtils.sign(y) == 0.0) { |
| 147 | 16 | x1 = x; y1 = y; |
| 148 | } else { |
|
| 149 | 8 | x1 = x3; x2 = x; |
| 150 | 8 | y1 = y3; y2 = y; |
| 151 | } |
|
| 152 | } |
|
| 153 | 66 | oldx = x; |
| 154 | 66 | i++; |
| 155 | } |
|
| 156 | 0 | throw new ConvergenceException("Maximum number of iterations exceeded."); |
| 157 | } |
|
| 158 | } |