1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.commons.math.analysis;
17
18 import java.io.Serializable;
19
20 import org.apache.commons.math.ConvergenceException;
21 import org.apache.commons.math.FunctionEvaluationException;
22
23
24 /***
25 * Implements a modified version of the
26 * <a href="http://mathworld.wolfram.com/SecantMethod.html">secant method</a>
27 * for approximating a zero of a real univariate function.
28 * <p>
29 * The algorithm is modified to maintain bracketing of a root by successive
30 * approximations. Because of forced bracketing, convergence may be slower than
31 * the unrestricted secant algorithm. However, this implementation should in
32 * general outperform the
33 * <a href="http://mathworld.wolfram.com/MethodofFalsePosition.html">
34 * regula falsi method.</a>
35 * <p>
36 * The function is assumed to be continuous but not necessarily smooth.
37 *
38 * @version $Revision: 1.17 $ $Date: 2004/07/17 21:19:39 $
39 */
40 public class SecantSolver extends UnivariateRealSolverImpl implements Serializable {
41
42 /*** Serializable version identifier */
43 static final long serialVersionUID = 1984971194738974867L;
44
45 /***
46 * Construct a solver for the given function.
47 * @param f function to solve.
48 */
49 public SecantSolver(UnivariateRealFunction f) {
50 super(f, 100, 1E-6);
51 }
52
53 /***
54 * Find a zero in the given interval.
55 *
56 * @param min the lower bound for the interval
57 * @param max the upper bound for the interval
58 * @param initial the start value to use (ignored)
59 * @return the value where the function is zero
60 * @throws ConvergenceException if the maximum iteration count is exceeded
61 * @throws FunctionEvaluationException if an error occurs evaluating the
62 * function
63 * @throws IllegalArgumentException if min is not less than max or the
64 * signs of the values of the function at the endpoints are not opposites
65 */
66 public double solve(double min, double max, double initial)
67 throws ConvergenceException, FunctionEvaluationException {
68
69 return solve(min, max);
70 }
71
72 /***
73 * Find a zero in the given interval.
74 * @param min the lower bound for the interval.
75 * @param max the upper bound for the interval.
76 * @return the value where the function is zero
77 * @throws ConvergenceException if the maximum iteration count is exceeded
78 * @throws FunctionEvaluationException if an error occurs evaluating the
79 * function
80 * @throws IllegalArgumentException if min is not less than max or the
81 * signs of the values of the function at the endpoints are not opposites
82 */
83 public double solve(double min, double max) throws ConvergenceException,
84 FunctionEvaluationException {
85
86 clearResult();
87 verifyBracketing(min, max, f);
88
89
90
91
92
93
94 double x0 = min;
95 double x1 = max;
96 double y0 = f.value(x0);
97 double y1 = f.value(x1);
98 double x2 = x0;
99 double y2 = y0;
100 double oldDelta = x2 - x1;
101 int i = 0;
102 while (i < maximalIterationCount) {
103 if (Math.abs(y2) < Math.abs(y1)) {
104 x0 = x1;
105 x1 = x2;
106 x2 = x0;
107 y0 = y1;
108 y1 = y2;
109 y2 = y0;
110 }
111 if (Math.abs(y1) <= functionValueAccuracy) {
112 setResult(x1, i);
113 return result;
114 }
115 if (Math.abs(oldDelta) <
116 Math.max(relativeAccuracy * Math.abs(x1), absoluteAccuracy)) {
117 setResult(x1, i);
118 return result;
119 }
120 double delta;
121 if (Math.abs(y1) > Math.abs(y0)) {
122
123 delta = 0.5 * oldDelta;
124 } else {
125 delta = (x0 - x1) / (1 - y0 / y1);
126 if (delta / oldDelta > 1) {
127
128
129 delta = 0.5 * oldDelta;
130 }
131 }
132 x0 = x1;
133 y0 = y1;
134 x1 = x1 + delta;
135 y1 = f.value(x1);
136 if ((y1 > 0) == (y2 > 0)) {
137
138 x2 = x0;
139 y2 = y0;
140 }
141 oldDelta = x2 - x1;
142 i++;
143 }
144 throw new ConvergenceException("Maximal iteration number exceeded" + i);
145 }
146
147 }