STK++ 0.9.13
STK_Algo_FindZero.h
Go to the documentation of this file.
1/*--------------------------------------------------------------------*/
2/* Copyright (C) 2004-2016 Serge Iovleff, Université Lille 1, Inria
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this program; if not, write to the
16 Free Software Foundation, Inc.,
17 59 Temple Place,
18 Suite 330,
19 Boston, MA 02111-1307
20 USA
21
22 Contact : S..._Dot_I..._At_stkpp_Dot_org (see copyright for ...)
23*/
24
25/*
26 * Project: stkpp::STatistiK
27 * Purpose: Method implementing Algorithms.
28 * Author: Serge Iovleff, S..._Dot_I..._At_stkpp_Dot_org (see copyright for ...)
29 **/
30
35#ifndef STK_ALGO_FINDZERO_H
36#define STK_ALGO_FINDZERO_H
37
38#include <Sdk.h>
39
40#include "STK_IFunction.h"
41
42#define MAX_ITER 1000
43
44namespace STK
45{
46
47namespace Algo
48{
49// forward declaration
50template <class Function>
51Real BrentMethod( IFunction<Function> const& f, Real const& x0, Real const& x1, Real tol);
52template <class Function>
53Real SecantMethod( IFunction<Function> const& f, Real const& x0, Real const& x1, Real tol);
54template <class Function>
55Real findZero( IFunction<Function> const& f, Real const& x0, Real const& x1, Real tol);
56
78template <class Function>
80{
81 Real a = x0, b = x1, fa = f(x0), fb = f(x1);
82 // set low and high values
83 if (std::abs(fa) < std::abs(fb))
84 {
85 std::swap(a, b);
86 std::swap(fa, fb);
87 }
88 // trivial case
89 if (std::abs(fb)<tol) return b;
90 // if root is bracketed use Brent method
91 if (fa * fb <0.) { return BrentMethod(f, a, b, tol);}
92 // start secant iterations
93 while( std::abs(b-a)>tol )
94 {
95 Real s = b - fb * (b - a) / (fb - fa);
96 Real delta = b-s;
97 // if we are out of bound, we try a desperate step
98 if (s<f.xmin())
99 { s = (b + std::max(f.xmin(), b - std::abs(b-a))/8 )/2.; delta = b-s;}
100 if (s>f.xmax())
101 { s = (b + std::min(f.xmax(), b + std::abs(b-a))/8 )/2.; delta = b-s;}
102 // compute f(s)
103 Real fs = f(s);
104 // check if we can switch to Brent method
105 if (fb * fs < 0) { return BrentMethod(f, b, s, tol); }
106 // handle divergence
107 if (std::abs(fs)>std::abs(fb))// divergence
108 {
109 bool dv = true;
110 for (int i=0; i<16; i++)
111 {
112 delta /=2.;
113 s = b - delta;
114 fs = f(s);
115 // check if we can switch to Brent method
116 if (fb * fs < 0) { return BrentMethod(f, b, s, tol); }
117 // ok !
118 if (std::abs(fs)<std::abs(fb)) { dv = false; break ;}
119 }
120 // we were not lucky...
121 if (dv) return Arithmetic<Real>::NA();
122 }
123 // update
124 a =b; fa = fb;
125 b =s; fb = fs;
126 // set low and high values
127 if (std::abs(fa) < std::abs(fb))
128 {
129 std::swap(a, b);
130 std::swap(fa, fb);
131 }
132 // trivial case
133 if (std::abs(fb) <tol) return b;
134 }
135 return b;
136}
137
147template <class Function>
149{
150 Real a = x0, b = x1, fa = f(x0), fb = f(x1);
151 // set low and high values
152 if (std::abs(fa) < std::abs(fb))
153 {
154 std::swap(a, b);
155 std::swap(fa, fb);
156 }
157 // trivial case
158 if (std::abs(fb)<tol) return b;
159 // if root is not bracketed secant method have to be used
160 if (fa * fb >0.) { return SecantMethod(f, a, b, tol);}
161 Real bkm1 = a, fbkm1 = fa;
162 bool mflag = true;
163 Real bkm2 = bkm1; // value of bkm2 is not used at the first iteration as mflag = true
164
165 int iter =0;
166#ifdef STK_ANALYSIS_VERBOSE
167 stk_cout << _T("iter = ") << iter <<_T(". bkm1, a, b = ") << bkm1 << _T(" ") << a << _T(" ") << b << _T("\n");
168 stk_cout << _T("iter = ") << iter <<_T(". fbkm1, fak, fbk = ") << fbkm1 << _T(" ") << fa << _T(" ") << fb << _T("\n");
169#endif
170 // start Brent iterations
171 while( std::abs(b-a)>tol )
172 {
173 iter++;
174 Real s;
175 if ((fa != fbkm1) && (fb != fbkm1)) // inverse quadratic approximation
176 {
177 Real dab = fa - fb, dac = fa -fbkm1, dbc = fb -fbkm1;
178 s = a * fb * fbkm1 / dab / dac
179 + b * fa * fbkm1 / -dab / dbc
180 + bkm1 * fa * fb / dac / dbc;
181 }
182 else // secante method
183 { s = b - fb * (b - a) / (fb - fa);}
184 // check if we shall fall-back to dichotomy
185 Real tmp = (3. * a + b) / 4., diff1 =std::abs(b - bkm1), diff2 = std::abs(bkm1-bkm2);
186 if (!( ((s > tmp) && (s < b)) || ((s < tmp) && (s > b)) ) // s not between b and tmp
187 ||( mflag &&( (std::abs(s-b) >= diff1 / 2.)||(diff1 < tol)))
188 ||(!mflag &&( (std::abs(s-b) >= diff2 / 2.)||(diff2 < tol)))
189 ||(s<=f.xmin())||(s>=f.xmax())
190 )
191 {
192 s = (a + b) / 2.;
193 mflag = true;
194 }
195 else { mflag = false;}
196
197 Real fs = f(s);
198 // save history
199 bkm2 = bkm1; bkm1 = b; fbkm1 = fb;
200 // check for bracketing the root
201 if (fa * fs < 0) { b = s; fb = fs; }
202 else { a = s; fa = fs; }
203 // if |f(a)| < |f(b)| then swap (a, b)
204 if (std::abs(fa) < std::abs(fb))
205 {
206 std::swap(a, b);
207 std::swap(fa, fb);
208 }
209#ifdef STK_ANALYSIS_VERBOSE
210 stk_cout << _T("iter = ") << iter <<_T(". bkm1, ak, b = ") << bkm1 << _T(" ") << ak << _T(" ") << b << _T("\n");
211 stk_cout << _T("iter = ") << iter <<_T(". fbkm1, fa, fb = ") << fbkm1 << _T(" ") << fa << _T(" ") << fb << _T("\n");
212#endif
213 if (std::abs(fb) < tol ) return b;
214 if (iter > MAX_ITER) return Arithmetic<Real>::NA();
215 }
216 return b;
217}
218
230template <class Function>
232{
233 if (x0<f.xmin() || x0>f.xmax() || x1<f.xmin() || x1>f.xmax() || tol<=0 )
234 return Arithmetic<Real>::NA();
235 return BrentMethod(f, x0, x1, tol);
236}
237
238} // namespace Algo
239
240} // namespace STK
241
242#undef MAX_ITER
243#endif /*STK_ALGO_FINDZERO_H*/
In this file we define Interface base class for Real functions.
#define MAX_ITER
Definition STK_Svd.h:49
#define stk_cout
Standard stk output stream.
#define _T(x)
Let x unmodified.
This file include all the other header files of the project Sdk.
The MultidimRegression class allows to regress a multidimensional output variable among a multivariat...
Real SecantMethod(IFunction< Function > const &f, Real const &x0, Real const &x1, Real tol)
apply the secant method for finding the zero of a function.
Real BrentMethod(IFunction< Function > const &f, Real const &x0, Real const &x1, Real tol)
perform the brent's algorithm.
Real findZero(IFunction< Function > const &f, Real const &x0, Real const &x1, Real tol)
find the zero of a function.
double Real
STK fundamental type of Real values.
The namespace STK is the main domain space of the Statistical ToolKit project.
static Type NA()
Adding a Non Available (NA) special number.