Chris@16
|
1 // (C) Copyright John Maddock 2006.
|
Chris@16
|
2 // Use, modification and distribution are subject to the
|
Chris@16
|
3 // Boost Software License, Version 1.0. (See accompanying file
|
Chris@16
|
4 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
5
|
Chris@16
|
6 #ifndef BOOST_MATH_TOOLS_NEWTON_SOLVER_HPP
|
Chris@16
|
7 #define BOOST_MATH_TOOLS_NEWTON_SOLVER_HPP
|
Chris@16
|
8
|
Chris@16
|
9 #ifdef _MSC_VER
|
Chris@16
|
10 #pragma once
|
Chris@16
|
11 #endif
|
Chris@16
|
12
|
Chris@16
|
13 #include <utility>
|
Chris@16
|
14 #include <boost/config/no_tr1/cmath.hpp>
|
Chris@16
|
15 #include <stdexcept>
|
Chris@16
|
16
|
Chris@16
|
17 #include <boost/math/tools/config.hpp>
|
Chris@16
|
18 #include <boost/cstdint.hpp>
|
Chris@16
|
19 #include <boost/assert.hpp>
|
Chris@16
|
20 #include <boost/throw_exception.hpp>
|
Chris@16
|
21
|
Chris@16
|
22 #ifdef BOOST_MSVC
|
Chris@16
|
23 #pragma warning(push)
|
Chris@16
|
24 #pragma warning(disable: 4512)
|
Chris@16
|
25 #endif
|
Chris@16
|
26 #include <boost/math/tools/tuple.hpp>
|
Chris@16
|
27 #ifdef BOOST_MSVC
|
Chris@16
|
28 #pragma warning(pop)
|
Chris@16
|
29 #endif
|
Chris@16
|
30
|
Chris@16
|
31 #include <boost/math/special_functions/sign.hpp>
|
Chris@16
|
32 #include <boost/math/tools/toms748_solve.hpp>
|
Chris@16
|
33 #include <boost/math/policies/error_handling.hpp>
|
Chris@16
|
34
|
Chris@16
|
35 namespace boost{ namespace math{ namespace tools{
|
Chris@16
|
36
|
Chris@16
|
37 namespace detail{
|
Chris@16
|
38
|
Chris@16
|
39 template <class Tuple, class T>
|
Chris@16
|
40 inline void unpack_0(const Tuple& t, T& val)
|
Chris@16
|
41 { val = boost::math::get<0>(t); }
|
Chris@16
|
42
|
Chris@16
|
43 template <class F, class T>
|
Chris@16
|
44 void handle_zero_derivative(F f,
|
Chris@16
|
45 T& last_f0,
|
Chris@16
|
46 const T& f0,
|
Chris@16
|
47 T& delta,
|
Chris@16
|
48 T& result,
|
Chris@16
|
49 T& guess,
|
Chris@16
|
50 const T& min,
|
Chris@16
|
51 const T& max)
|
Chris@16
|
52 {
|
Chris@16
|
53 if(last_f0 == 0)
|
Chris@16
|
54 {
|
Chris@16
|
55 // this must be the first iteration, pretend that we had a
|
Chris@16
|
56 // previous one at either min or max:
|
Chris@16
|
57 if(result == min)
|
Chris@16
|
58 {
|
Chris@16
|
59 guess = max;
|
Chris@16
|
60 }
|
Chris@16
|
61 else
|
Chris@16
|
62 {
|
Chris@16
|
63 guess = min;
|
Chris@16
|
64 }
|
Chris@16
|
65 unpack_0(f(guess), last_f0);
|
Chris@16
|
66 delta = guess - result;
|
Chris@16
|
67 }
|
Chris@16
|
68 if(sign(last_f0) * sign(f0) < 0)
|
Chris@16
|
69 {
|
Chris@16
|
70 // we've crossed over so move in opposite direction to last step:
|
Chris@16
|
71 if(delta < 0)
|
Chris@16
|
72 {
|
Chris@16
|
73 delta = (result - min) / 2;
|
Chris@16
|
74 }
|
Chris@16
|
75 else
|
Chris@16
|
76 {
|
Chris@16
|
77 delta = (result - max) / 2;
|
Chris@16
|
78 }
|
Chris@16
|
79 }
|
Chris@16
|
80 else
|
Chris@16
|
81 {
|
Chris@16
|
82 // move in same direction as last step:
|
Chris@16
|
83 if(delta < 0)
|
Chris@16
|
84 {
|
Chris@16
|
85 delta = (result - max) / 2;
|
Chris@16
|
86 }
|
Chris@16
|
87 else
|
Chris@16
|
88 {
|
Chris@16
|
89 delta = (result - min) / 2;
|
Chris@16
|
90 }
|
Chris@16
|
91 }
|
Chris@16
|
92 }
|
Chris@16
|
93
|
Chris@16
|
94 } // namespace
|
Chris@16
|
95
|
Chris@16
|
96 template <class F, class T, class Tol, class Policy>
|
Chris@16
|
97 std::pair<T, T> bisect(F f, T min, T max, Tol tol, boost::uintmax_t& max_iter, const Policy& pol)
|
Chris@16
|
98 {
|
Chris@16
|
99 T fmin = f(min);
|
Chris@16
|
100 T fmax = f(max);
|
Chris@16
|
101 if(fmin == 0)
|
Chris@16
|
102 return std::make_pair(min, min);
|
Chris@16
|
103 if(fmax == 0)
|
Chris@16
|
104 return std::make_pair(max, max);
|
Chris@16
|
105
|
Chris@16
|
106 //
|
Chris@16
|
107 // Error checking:
|
Chris@16
|
108 //
|
Chris@16
|
109 static const char* function = "boost::math::tools::bisect<%1%>";
|
Chris@16
|
110 if(min >= max)
|
Chris@16
|
111 {
|
Chris@101
|
112 return boost::math::detail::pair_from_single(policies::raise_evaluation_error(function,
|
Chris@101
|
113 "Arguments in wrong order in boost::math::tools::bisect (first arg=%1%)", min, pol));
|
Chris@16
|
114 }
|
Chris@16
|
115 if(fmin * fmax >= 0)
|
Chris@16
|
116 {
|
Chris@101
|
117 return boost::math::detail::pair_from_single(policies::raise_evaluation_error(function,
|
Chris@101
|
118 "No change of sign in boost::math::tools::bisect, either there is no root to find, or there are multiple roots in the interval (f(min) = %1%).", fmin, pol));
|
Chris@16
|
119 }
|
Chris@16
|
120
|
Chris@16
|
121 //
|
Chris@16
|
122 // Three function invocations so far:
|
Chris@16
|
123 //
|
Chris@16
|
124 boost::uintmax_t count = max_iter;
|
Chris@16
|
125 if(count < 3)
|
Chris@16
|
126 count = 0;
|
Chris@16
|
127 else
|
Chris@16
|
128 count -= 3;
|
Chris@16
|
129
|
Chris@16
|
130 while(count && (0 == tol(min, max)))
|
Chris@16
|
131 {
|
Chris@16
|
132 T mid = (min + max) / 2;
|
Chris@16
|
133 T fmid = f(mid);
|
Chris@16
|
134 if((mid == max) || (mid == min))
|
Chris@16
|
135 break;
|
Chris@16
|
136 if(fmid == 0)
|
Chris@16
|
137 {
|
Chris@16
|
138 min = max = mid;
|
Chris@16
|
139 break;
|
Chris@16
|
140 }
|
Chris@16
|
141 else if(sign(fmid) * sign(fmin) < 0)
|
Chris@16
|
142 {
|
Chris@16
|
143 max = mid;
|
Chris@16
|
144 fmax = fmid;
|
Chris@16
|
145 }
|
Chris@16
|
146 else
|
Chris@16
|
147 {
|
Chris@16
|
148 min = mid;
|
Chris@16
|
149 fmin = fmid;
|
Chris@16
|
150 }
|
Chris@16
|
151 --count;
|
Chris@16
|
152 }
|
Chris@16
|
153
|
Chris@16
|
154 max_iter -= count;
|
Chris@16
|
155
|
Chris@16
|
156 #ifdef BOOST_MATH_INSTRUMENT
|
Chris@16
|
157 std::cout << "Bisection iteration, final count = " << max_iter << std::endl;
|
Chris@16
|
158
|
Chris@16
|
159 static boost::uintmax_t max_count = 0;
|
Chris@16
|
160 if(max_iter > max_count)
|
Chris@16
|
161 {
|
Chris@16
|
162 max_count = max_iter;
|
Chris@16
|
163 std::cout << "Maximum iterations: " << max_iter << std::endl;
|
Chris@16
|
164 }
|
Chris@16
|
165 #endif
|
Chris@16
|
166
|
Chris@16
|
167 return std::make_pair(min, max);
|
Chris@16
|
168 }
|
Chris@16
|
169
|
Chris@16
|
170 template <class F, class T, class Tol>
|
Chris@16
|
171 inline std::pair<T, T> bisect(F f, T min, T max, Tol tol, boost::uintmax_t& max_iter)
|
Chris@16
|
172 {
|
Chris@16
|
173 return bisect(f, min, max, tol, max_iter, policies::policy<>());
|
Chris@16
|
174 }
|
Chris@16
|
175
|
Chris@16
|
176 template <class F, class T, class Tol>
|
Chris@16
|
177 inline std::pair<T, T> bisect(F f, T min, T max, Tol tol)
|
Chris@16
|
178 {
|
Chris@16
|
179 boost::uintmax_t m = (std::numeric_limits<boost::uintmax_t>::max)();
|
Chris@16
|
180 return bisect(f, min, max, tol, m, policies::policy<>());
|
Chris@16
|
181 }
|
Chris@16
|
182
|
Chris@16
|
183 template <class F, class T>
|
Chris@16
|
184 T newton_raphson_iterate(F f, T guess, T min, T max, int digits, boost::uintmax_t& max_iter)
|
Chris@16
|
185 {
|
Chris@16
|
186 BOOST_MATH_STD_USING
|
Chris@16
|
187
|
Chris@16
|
188 T f0(0), f1, last_f0(0);
|
Chris@16
|
189 T result = guess;
|
Chris@16
|
190
|
Chris@16
|
191 T factor = static_cast<T>(ldexp(1.0, 1 - digits));
|
Chris@16
|
192 T delta = 1;
|
Chris@16
|
193 T delta1 = tools::max_value<T>();
|
Chris@16
|
194 T delta2 = tools::max_value<T>();
|
Chris@16
|
195
|
Chris@16
|
196 boost::uintmax_t count(max_iter);
|
Chris@16
|
197
|
Chris@16
|
198 do{
|
Chris@16
|
199 last_f0 = f0;
|
Chris@16
|
200 delta2 = delta1;
|
Chris@16
|
201 delta1 = delta;
|
Chris@16
|
202 boost::math::tie(f0, f1) = f(result);
|
Chris@16
|
203 if(0 == f0)
|
Chris@16
|
204 break;
|
Chris@16
|
205 if(f1 == 0)
|
Chris@16
|
206 {
|
Chris@16
|
207 // Oops zero derivative!!!
|
Chris@16
|
208 #ifdef BOOST_MATH_INSTRUMENT
|
Chris@16
|
209 std::cout << "Newton iteration, zero derivative found" << std::endl;
|
Chris@16
|
210 #endif
|
Chris@16
|
211 detail::handle_zero_derivative(f, last_f0, f0, delta, result, guess, min, max);
|
Chris@16
|
212 }
|
Chris@16
|
213 else
|
Chris@16
|
214 {
|
Chris@16
|
215 delta = f0 / f1;
|
Chris@16
|
216 }
|
Chris@16
|
217 #ifdef BOOST_MATH_INSTRUMENT
|
Chris@16
|
218 std::cout << "Newton iteration, delta = " << delta << std::endl;
|
Chris@16
|
219 #endif
|
Chris@16
|
220 if(fabs(delta * 2) > fabs(delta2))
|
Chris@16
|
221 {
|
Chris@16
|
222 // last two steps haven't converged, try bisection:
|
Chris@16
|
223 delta = (delta > 0) ? (result - min) / 2 : (result - max) / 2;
|
Chris@16
|
224 }
|
Chris@16
|
225 guess = result;
|
Chris@16
|
226 result -= delta;
|
Chris@16
|
227 if(result <= min)
|
Chris@16
|
228 {
|
Chris@16
|
229 delta = 0.5F * (guess - min);
|
Chris@16
|
230 result = guess - delta;
|
Chris@16
|
231 if((result == min) || (result == max))
|
Chris@16
|
232 break;
|
Chris@16
|
233 }
|
Chris@16
|
234 else if(result >= max)
|
Chris@16
|
235 {
|
Chris@16
|
236 delta = 0.5F * (guess - max);
|
Chris@16
|
237 result = guess - delta;
|
Chris@16
|
238 if((result == min) || (result == max))
|
Chris@16
|
239 break;
|
Chris@16
|
240 }
|
Chris@16
|
241 // update brackets:
|
Chris@16
|
242 if(delta > 0)
|
Chris@16
|
243 max = guess;
|
Chris@16
|
244 else
|
Chris@16
|
245 min = guess;
|
Chris@16
|
246 }while(--count && (fabs(result * factor) < fabs(delta)));
|
Chris@16
|
247
|
Chris@16
|
248 max_iter -= count;
|
Chris@16
|
249
|
Chris@16
|
250 #ifdef BOOST_MATH_INSTRUMENT
|
Chris@16
|
251 std::cout << "Newton Raphson iteration, final count = " << max_iter << std::endl;
|
Chris@16
|
252
|
Chris@16
|
253 static boost::uintmax_t max_count = 0;
|
Chris@16
|
254 if(max_iter > max_count)
|
Chris@16
|
255 {
|
Chris@16
|
256 max_count = max_iter;
|
Chris@16
|
257 std::cout << "Maximum iterations: " << max_iter << std::endl;
|
Chris@16
|
258 }
|
Chris@16
|
259 #endif
|
Chris@16
|
260
|
Chris@16
|
261 return result;
|
Chris@16
|
262 }
|
Chris@16
|
263
|
Chris@16
|
264 template <class F, class T>
|
Chris@16
|
265 inline T newton_raphson_iterate(F f, T guess, T min, T max, int digits)
|
Chris@16
|
266 {
|
Chris@16
|
267 boost::uintmax_t m = (std::numeric_limits<boost::uintmax_t>::max)();
|
Chris@16
|
268 return newton_raphson_iterate(f, guess, min, max, digits, m);
|
Chris@16
|
269 }
|
Chris@16
|
270
|
Chris@16
|
271 template <class F, class T>
|
Chris@16
|
272 T halley_iterate(F f, T guess, T min, T max, int digits, boost::uintmax_t& max_iter)
|
Chris@16
|
273 {
|
Chris@16
|
274 BOOST_MATH_STD_USING
|
Chris@16
|
275
|
Chris@16
|
276 T f0(0), f1, f2;
|
Chris@16
|
277 T result = guess;
|
Chris@16
|
278
|
Chris@16
|
279 T factor = static_cast<T>(ldexp(1.0, 1 - digits));
|
Chris@16
|
280 T delta = (std::max)(T(10000000 * guess), T(10000000)); // arbitarily large delta
|
Chris@16
|
281 T last_f0 = 0;
|
Chris@16
|
282 T delta1 = delta;
|
Chris@16
|
283 T delta2 = delta;
|
Chris@16
|
284
|
Chris@16
|
285 bool out_of_bounds_sentry = false;
|
Chris@16
|
286
|
Chris@16
|
287 #ifdef BOOST_MATH_INSTRUMENT
|
Chris@16
|
288 std::cout << "Halley iteration, limit = " << factor << std::endl;
|
Chris@16
|
289 #endif
|
Chris@16
|
290
|
Chris@16
|
291 boost::uintmax_t count(max_iter);
|
Chris@16
|
292
|
Chris@16
|
293 do{
|
Chris@16
|
294 last_f0 = f0;
|
Chris@16
|
295 delta2 = delta1;
|
Chris@16
|
296 delta1 = delta;
|
Chris@16
|
297 boost::math::tie(f0, f1, f2) = f(result);
|
Chris@16
|
298
|
Chris@16
|
299 BOOST_MATH_INSTRUMENT_VARIABLE(f0);
|
Chris@16
|
300 BOOST_MATH_INSTRUMENT_VARIABLE(f1);
|
Chris@16
|
301 BOOST_MATH_INSTRUMENT_VARIABLE(f2);
|
Chris@16
|
302
|
Chris@16
|
303 if(0 == f0)
|
Chris@16
|
304 break;
|
Chris@101
|
305 if(f1 == 0)
|
Chris@16
|
306 {
|
Chris@16
|
307 // Oops zero derivative!!!
|
Chris@16
|
308 #ifdef BOOST_MATH_INSTRUMENT
|
Chris@16
|
309 std::cout << "Halley iteration, zero derivative found" << std::endl;
|
Chris@16
|
310 #endif
|
Chris@16
|
311 detail::handle_zero_derivative(f, last_f0, f0, delta, result, guess, min, max);
|
Chris@16
|
312 }
|
Chris@16
|
313 else
|
Chris@16
|
314 {
|
Chris@16
|
315 if(f2 != 0)
|
Chris@16
|
316 {
|
Chris@16
|
317 T denom = 2 * f0;
|
Chris@16
|
318 T num = 2 * f1 - f0 * (f2 / f1);
|
Chris@16
|
319
|
Chris@16
|
320 BOOST_MATH_INSTRUMENT_VARIABLE(denom);
|
Chris@16
|
321 BOOST_MATH_INSTRUMENT_VARIABLE(num);
|
Chris@16
|
322
|
Chris@16
|
323 if((fabs(num) < 1) && (fabs(denom) >= fabs(num) * tools::max_value<T>()))
|
Chris@16
|
324 {
|
Chris@16
|
325 // possible overflow, use Newton step:
|
Chris@16
|
326 delta = f0 / f1;
|
Chris@16
|
327 }
|
Chris@16
|
328 else
|
Chris@16
|
329 delta = denom / num;
|
Chris@16
|
330 if(delta * f1 / f0 < 0)
|
Chris@16
|
331 {
|
Chris@16
|
332 // Oh dear, we have a problem as Newton and Halley steps
|
Chris@16
|
333 // disagree about which way we should move. Probably
|
Chris@16
|
334 // there is cancelation error in the calculation of the
|
Chris@16
|
335 // Halley step, or else the derivatives are so small
|
Chris@16
|
336 // that their values are basically trash. We will move
|
Chris@16
|
337 // in the direction indicated by a Newton step, but
|
Chris@16
|
338 // by no more than twice the current guess value, otherwise
|
Chris@16
|
339 // we can jump way out of bounds if we're not careful.
|
Chris@16
|
340 // See https://svn.boost.org/trac/boost/ticket/8314.
|
Chris@16
|
341 delta = f0 / f1;
|
Chris@16
|
342 if(fabs(delta) > 2 * fabs(guess))
|
Chris@16
|
343 delta = (delta < 0 ? -1 : 1) * 2 * fabs(guess);
|
Chris@16
|
344 }
|
Chris@16
|
345 }
|
Chris@16
|
346 else
|
Chris@16
|
347 delta = f0 / f1;
|
Chris@16
|
348 }
|
Chris@16
|
349 #ifdef BOOST_MATH_INSTRUMENT
|
Chris@16
|
350 std::cout << "Halley iteration, delta = " << delta << std::endl;
|
Chris@16
|
351 #endif
|
Chris@16
|
352 T convergence = fabs(delta / delta2);
|
Chris@16
|
353 if((convergence > 0.8) && (convergence < 2))
|
Chris@16
|
354 {
|
Chris@16
|
355 // last two steps haven't converged, try bisection:
|
Chris@16
|
356 delta = (delta > 0) ? (result - min) / 2 : (result - max) / 2;
|
Chris@16
|
357 if(fabs(delta) > result)
|
Chris@16
|
358 delta = sign(delta) * result; // protect against huge jumps!
|
Chris@16
|
359 // reset delta2 so that this branch will *not* be taken on the
|
Chris@16
|
360 // next iteration:
|
Chris@16
|
361 delta2 = delta * 3;
|
Chris@16
|
362 BOOST_MATH_INSTRUMENT_VARIABLE(delta);
|
Chris@16
|
363 }
|
Chris@16
|
364 guess = result;
|
Chris@16
|
365 result -= delta;
|
Chris@16
|
366 BOOST_MATH_INSTRUMENT_VARIABLE(result);
|
Chris@16
|
367
|
Chris@16
|
368 // check for out of bounds step:
|
Chris@16
|
369 if(result < min)
|
Chris@16
|
370 {
|
Chris@16
|
371 T diff = ((fabs(min) < 1) && (fabs(result) > 1) && (tools::max_value<T>() / fabs(result) < fabs(min))) ? T(1000) : T(result / min);
|
Chris@16
|
372 if(fabs(diff) < 1)
|
Chris@16
|
373 diff = 1 / diff;
|
Chris@16
|
374 if(!out_of_bounds_sentry && (diff > 0) && (diff < 3))
|
Chris@16
|
375 {
|
Chris@16
|
376 // Only a small out of bounds step, lets assume that the result
|
Chris@16
|
377 // is probably approximately at min:
|
Chris@16
|
378 delta = 0.99f * (guess - min);
|
Chris@16
|
379 result = guess - delta;
|
Chris@16
|
380 out_of_bounds_sentry = true; // only take this branch once!
|
Chris@16
|
381 }
|
Chris@16
|
382 else
|
Chris@16
|
383 {
|
Chris@16
|
384 delta = (guess - min) / 2;
|
Chris@16
|
385 result = guess - delta;
|
Chris@16
|
386 if((result == min) || (result == max))
|
Chris@16
|
387 break;
|
Chris@16
|
388 }
|
Chris@16
|
389 }
|
Chris@16
|
390 else if(result > max)
|
Chris@16
|
391 {
|
Chris@16
|
392 T diff = ((fabs(max) < 1) && (fabs(result) > 1) && (tools::max_value<T>() / fabs(result) < fabs(max))) ? T(1000) : T(result / max);
|
Chris@16
|
393 if(fabs(diff) < 1)
|
Chris@16
|
394 diff = 1 / diff;
|
Chris@16
|
395 if(!out_of_bounds_sentry && (diff > 0) && (diff < 3))
|
Chris@16
|
396 {
|
Chris@16
|
397 // Only a small out of bounds step, lets assume that the result
|
Chris@16
|
398 // is probably approximately at min:
|
Chris@16
|
399 delta = 0.99f * (guess - max);
|
Chris@16
|
400 result = guess - delta;
|
Chris@16
|
401 out_of_bounds_sentry = true; // only take this branch once!
|
Chris@16
|
402 }
|
Chris@16
|
403 else
|
Chris@16
|
404 {
|
Chris@16
|
405 delta = (guess - max) / 2;
|
Chris@16
|
406 result = guess - delta;
|
Chris@16
|
407 if((result == min) || (result == max))
|
Chris@16
|
408 break;
|
Chris@16
|
409 }
|
Chris@16
|
410 }
|
Chris@16
|
411 // update brackets:
|
Chris@16
|
412 if(delta > 0)
|
Chris@16
|
413 max = guess;
|
Chris@16
|
414 else
|
Chris@16
|
415 min = guess;
|
Chris@16
|
416 }while(--count && (fabs(result * factor) < fabs(delta)));
|
Chris@16
|
417
|
Chris@16
|
418 max_iter -= count;
|
Chris@16
|
419
|
Chris@16
|
420 #ifdef BOOST_MATH_INSTRUMENT
|
Chris@16
|
421 std::cout << "Halley iteration, final count = " << max_iter << std::endl;
|
Chris@16
|
422 #endif
|
Chris@16
|
423
|
Chris@16
|
424 return result;
|
Chris@16
|
425 }
|
Chris@16
|
426
|
Chris@16
|
427 template <class F, class T>
|
Chris@16
|
428 inline T halley_iterate(F f, T guess, T min, T max, int digits)
|
Chris@16
|
429 {
|
Chris@16
|
430 boost::uintmax_t m = (std::numeric_limits<boost::uintmax_t>::max)();
|
Chris@16
|
431 return halley_iterate(f, guess, min, max, digits, m);
|
Chris@16
|
432 }
|
Chris@16
|
433
|
Chris@16
|
434 template <class F, class T>
|
Chris@16
|
435 T schroeder_iterate(F f, T guess, T min, T max, int digits, boost::uintmax_t& max_iter)
|
Chris@16
|
436 {
|
Chris@16
|
437 BOOST_MATH_STD_USING
|
Chris@16
|
438
|
Chris@16
|
439 T f0(0), f1, f2, last_f0(0);
|
Chris@16
|
440 T result = guess;
|
Chris@16
|
441
|
Chris@16
|
442 T factor = static_cast<T>(ldexp(1.0, 1 - digits));
|
Chris@16
|
443 T delta = 0;
|
Chris@16
|
444 T delta1 = tools::max_value<T>();
|
Chris@16
|
445 T delta2 = tools::max_value<T>();
|
Chris@16
|
446
|
Chris@16
|
447 #ifdef BOOST_MATH_INSTRUMENT
|
Chris@16
|
448 std::cout << "Schroeder iteration, limit = " << factor << std::endl;
|
Chris@16
|
449 #endif
|
Chris@16
|
450
|
Chris@16
|
451 boost::uintmax_t count(max_iter);
|
Chris@16
|
452
|
Chris@16
|
453 do{
|
Chris@16
|
454 last_f0 = f0;
|
Chris@16
|
455 delta2 = delta1;
|
Chris@16
|
456 delta1 = delta;
|
Chris@16
|
457 boost::math::tie(f0, f1, f2) = f(result);
|
Chris@16
|
458 if(0 == f0)
|
Chris@16
|
459 break;
|
Chris@16
|
460 if((f1 == 0) && (f2 == 0))
|
Chris@16
|
461 {
|
Chris@16
|
462 // Oops zero derivative!!!
|
Chris@16
|
463 #ifdef BOOST_MATH_INSTRUMENT
|
Chris@16
|
464 std::cout << "Halley iteration, zero derivative found" << std::endl;
|
Chris@16
|
465 #endif
|
Chris@16
|
466 detail::handle_zero_derivative(f, last_f0, f0, delta, result, guess, min, max);
|
Chris@16
|
467 }
|
Chris@16
|
468 else
|
Chris@16
|
469 {
|
Chris@16
|
470 T ratio = f0 / f1;
|
Chris@16
|
471 if(ratio / result < 0.1)
|
Chris@16
|
472 {
|
Chris@16
|
473 delta = ratio + (f2 / (2 * f1)) * ratio * ratio;
|
Chris@16
|
474 // check second derivative doesn't over compensate:
|
Chris@16
|
475 if(delta * ratio < 0)
|
Chris@16
|
476 delta = ratio;
|
Chris@16
|
477 }
|
Chris@16
|
478 else
|
Chris@16
|
479 delta = ratio; // fall back to Newton iteration.
|
Chris@16
|
480 }
|
Chris@16
|
481 if(fabs(delta * 2) > fabs(delta2))
|
Chris@16
|
482 {
|
Chris@16
|
483 // last two steps haven't converged, try bisection:
|
Chris@16
|
484 delta = (delta > 0) ? (result - min) / 2 : (result - max) / 2;
|
Chris@16
|
485 }
|
Chris@16
|
486 guess = result;
|
Chris@16
|
487 result -= delta;
|
Chris@16
|
488 #ifdef BOOST_MATH_INSTRUMENT
|
Chris@16
|
489 std::cout << "Halley iteration, delta = " << delta << std::endl;
|
Chris@16
|
490 #endif
|
Chris@16
|
491 if(result <= min)
|
Chris@16
|
492 {
|
Chris@16
|
493 delta = 0.5F * (guess - min);
|
Chris@16
|
494 result = guess - delta;
|
Chris@16
|
495 if((result == min) || (result == max))
|
Chris@16
|
496 break;
|
Chris@16
|
497 }
|
Chris@16
|
498 else if(result >= max)
|
Chris@16
|
499 {
|
Chris@16
|
500 delta = 0.5F * (guess - max);
|
Chris@16
|
501 result = guess - delta;
|
Chris@16
|
502 if((result == min) || (result == max))
|
Chris@16
|
503 break;
|
Chris@16
|
504 }
|
Chris@16
|
505 // update brackets:
|
Chris@16
|
506 if(delta > 0)
|
Chris@16
|
507 max = guess;
|
Chris@16
|
508 else
|
Chris@16
|
509 min = guess;
|
Chris@16
|
510 }while(--count && (fabs(result * factor) < fabs(delta)));
|
Chris@16
|
511
|
Chris@16
|
512 max_iter -= count;
|
Chris@16
|
513
|
Chris@16
|
514 #ifdef BOOST_MATH_INSTRUMENT
|
Chris@16
|
515 std::cout << "Schroeder iteration, final count = " << max_iter << std::endl;
|
Chris@16
|
516
|
Chris@16
|
517 static boost::uintmax_t max_count = 0;
|
Chris@16
|
518 if(max_iter > max_count)
|
Chris@16
|
519 {
|
Chris@16
|
520 max_count = max_iter;
|
Chris@16
|
521 std::cout << "Maximum iterations: " << max_iter << std::endl;
|
Chris@16
|
522 }
|
Chris@16
|
523 #endif
|
Chris@16
|
524
|
Chris@16
|
525 return result;
|
Chris@16
|
526 }
|
Chris@16
|
527
|
Chris@16
|
528 template <class F, class T>
|
Chris@16
|
529 inline T schroeder_iterate(F f, T guess, T min, T max, int digits)
|
Chris@16
|
530 {
|
Chris@16
|
531 boost::uintmax_t m = (std::numeric_limits<boost::uintmax_t>::max)();
|
Chris@16
|
532 return schroeder_iterate(f, guess, min, max, digits, m);
|
Chris@16
|
533 }
|
Chris@16
|
534
|
Chris@16
|
535 } // namespace tools
|
Chris@16
|
536 } // namespace math
|
Chris@16
|
537 } // namespace boost
|
Chris@16
|
538
|
Chris@16
|
539 #endif // BOOST_MATH_TOOLS_NEWTON_SOLVER_HPP
|
Chris@16
|
540
|
Chris@16
|
541
|
Chris@16
|
542
|