2 * brentsolve- Root finding with the Brent-Dekker trick.
4 * Copyright (C) 2013 Christoph Zurnieden
6 * brentsolve is open software; you can redistribute it and/or modify it under
7 * the terms of the version 2.1 of the GNU Lesser General Public License
8 * as published by the Free Software Foundation.
10 * brentsolve is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
13 * Public License for more details.
15 * A copy of version 2.1 of the GNU Lesser General Public License is
16 * distributed with calc under the filename COPYING-LGPL. You should have
17 * received a copy with calc; if not, write to Free Software Foundation, Inc.
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * @(#) $Revision: 30.3 $
21 * @(#) $Id: brentsolve.cal,v 30.3 2013/08/11 08:41:38 chongo Exp $
22 * @(#) $Source: /usr/local/src/bin/calc/cal/RCS/brentsolve.cal,v $
24 * Under source code control: 2013/08/11 01:31:28
25 * File existed as early as: 2013
28 static resource_debug_level;
29 resource_debug_level = config("resource_debug", 0);
33 A short explanation is at http://en.wikipedia.org/wiki/Brent%27s_method
34 I tried to follow the description at wikipedia as much as possible to make
35 the slight changes I did more visible.
36 You may give http://people.sc.fsu.edu/~jburkardt/cpp_src/brent/brent.html a
37 short glimpse (Brent's originl Fortran77 versions and some translations of
43 define brentsolve(low, high,eps){
44 local a b c d fa fb fc fa2 fb2 fc2 s fs tmp tmp2 mflag i places;
50 eps = epsilon(epsilon()*1e-3);
51 places = highbit(1 + int( 1/epsilon() ) ) + 1;
73 if(abs(fa) < abs(fb)){
74 tmp = a; a = b; b = tmp;
75 tmp = fa; fa = fb; fb = tmp;
83 while(!(fb==0) && (abs(a-b) > eps)){
84 if((fa != fc) && (fb != fc)){
85 /* Inverse quadratic interpolation*/
88 s = bround(((fb^2*((fc*a)-(c*fa)))+(fb*((c*fa2)-(fc2*a)))+(b*((fc2*fa)
89 -(fc*fa2))))/((fc - fb)*(fa - fb)*(fc - fa)),places++);
93 s =bround( b - fb * (b - a) / (fb - fa),places++);
95 tmp2 = (3 * a + b) / 4;
96 if( (!( ((s > tmp2) && (s < b))||((s < tmp2) && (s > b))))
97 || (mflag && (abs(s - b) >= (abs(b - c) / 2)))
98 || (!mflag && (abs(s - b) >= (abs(c - d) / 2)))) {
103 if( (mflag && (abs(b - c) < eps))
104 || (!mflag && (abs(c - d) < eps))) {
123 if (abs(fa) < abs(fb)){
124 tmp = a; a = b; b = tmp;
125 tmp = fa; fa = fb; fb = tmp;
130 return newerror("brentsolve: does not converge");
138 A variation of the solver to accept functions named differently from "f". The
139 code should explain it.
141 define brentsolve2(low, high,which,eps){
142 local a b c d fa fb fc fa2 fb2 fc2 s fs tmp tmp2 mflag i places;
149 case 1: return newerror("brentsolve2: not enough argments");
150 case 2: eps = epsilon(epsilon()*1e-2);
152 case 3: eps = epsilon(epsilon()*1e-2);break;
155 places = highbit(1 + int(1/epsilon())) + 1;
160 case 1: fa = __CZ__invbeta(a);
161 fb = __CZ__invbeta(b); break;
162 case 2: fa = __CZ__invincgamma(a);
163 fb = __CZ__invincgamma(b); break;
165 default: fa = f(a);fb = f(b); break;
179 if(abs(fa) < abs(fb)){
180 tmp = a; a = b; b = tmp;
181 tmp = fa; fa = fb; fb = tmp;
189 while(!(fb==0) && (abs(a-b) > eps)){
191 if((fa != fc) && (fb != fc)){
192 /* Inverse quadratic interpolation*/
195 s = bround(((fb^2*((fc*a)-(c*fa)))+(fb*((c*fa2)-(fc2*a)))+(b*((fc2*fa)
196 -(fc*fa2))))/((fc - fb)*(fa - fb)*(fc - fa)),places);
201 s =bround( b - fb * (b - a) / (fb - fa),places);
204 tmp2 = (3 * a + b) / 4;
205 if( (!( ((s > tmp2) && (s < b))||((s < tmp2) && (s > b))))
206 || (mflag && (abs(s - b) >= (abs(b - c) / 2)))
207 || (!mflag && (abs(s - b) >= (abs(c - d) / 2)))) {
212 if( (mflag && (abs(b - c) < eps))
213 || (!mflag && (abs(c - d) < eps))) {
221 case 1: fs = __CZ__invbeta(s); break;
222 case 2: fs = __CZ__invincgamma(s); break;
224 default: fs = f(s); break;
237 if (abs(fa) < abs(fb)){
238 tmp = a; a = b; b = tmp;
239 tmp = fa; fa = fb; fb = tmp;
243 return newerror("brentsolve2: does not converge");
251 * restore internal function from resource debugging
253 config("resource_debug", resource_debug_level),;
254 if (config("resource_debug") & 3) {
255 print "brentsolve(low, high,eps)";
256 print "brentsolve2(low, high,which,eps)";