roots.hpp 17 KB

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