root_finding_examples.qbk 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  1. [section:root_finding_examples Examples of Root-Finding (with and without derivatives)]
  2. [import ../../example/root_finding_example.cpp]
  3. [import ../../example/root_finding_n_example.cpp]
  4. [import ../../example/root_finding_multiprecision_example.cpp]
  5. The examples demonstrate how to use the various tools for
  6. [@http://en.wikipedia.org/wiki/Root-finding_algorithm root finding].
  7. We start with the simple cube root function `cbrt` ( C++ standard function name
  8. [@http://en.cppreference.com/w/cpp/numeric/math/cbrt cbrt])
  9. showing root finding __cbrt_no_derivatives.
  10. We then show how use of derivatives can improve the speed of convergence.
  11. (But these examples are only a demonstration and do not try to make
  12. the ultimate improvements of an 'industrial-strength'
  13. implementation, for example, of `boost::math::cbrt`, mainly by using a better computed initial 'guess'
  14. at [@boost:/libs/math/include/boost/math/special_functions/cbrt.hpp cbrt.hpp]).
  15. Then we show how a higher root (__fifth_root) [super 5][radic] can be computed,
  16. and in
  17. [@../../example/root_finding_n_example.cpp root_finding_n_example.cpp]
  18. a generic method for the __nth_root that constructs the derivatives at compile-time.
  19. These methods should be applicable to other functions that can be differentiated easily.
  20. [section:cbrt_eg Finding the Cubed Root With and Without Derivatives]
  21. First some `#includes` that will be needed.
  22. [root_finding_include_1]
  23. [tip For clarity, `using` statements are provided to list what functions are being used in this example:
  24. you can, of course, partly or fully qualify the names in other ways.
  25. (For your application, you may wish to extract some parts into header files,
  26. but you should never use `using` statements globally in header files).]
  27. Let's suppose we want to find the root of a number ['a], and to start, compute the cube root.
  28. So the equation we want to solve is:
  29. [expression ['f(x) = x[cubed] -a]]
  30. We will first solve this without using any information
  31. about the slope or curvature of the cube root function.
  32. Fortunately, the cube-root function is 'Really Well Behaved' in that it is monotonic
  33. and has only one root (we leave negative values 'as an exercise for the student').
  34. We then show how adding what we can know about this function, first just the slope
  35. or 1st derivative ['f'(x)], will speed homing in on the solution.
  36. Lastly, we show how adding the curvature ['f''(x)] too will speed convergence even more.
  37. [h3:cbrt_no_derivatives Cube root function without derivatives]
  38. First we define a function object (functor):
  39. [root_finding_noderiv_1]
  40. Implementing the cube-root function itself is fairly trivial now:
  41. the hardest part is finding a good approximation to begin with.
  42. In this case we'll just divide the exponent by three.
  43. (There are better but more complex guess algorithms used in 'real life'.)
  44. [root_finding_noderiv_2]
  45. This snippet from `main()` in [@../../example/root_finding_example.cpp root_finding_example.cpp]
  46. shows how it can be used.
  47. [root_finding_main_1]
  48. [pre
  49. cbrt_noderiv(27) = 3
  50. cbrt_noderiv(28) = 3.0365889718756618
  51. ]
  52. The result of `bracket_and_solve_root` is a [@http://www.cplusplus.com/reference/utility/pair/ pair]
  53. of values that could be displayed.
  54. The number of bits separating them can be found using `float_distance(r.first, r.second)`.
  55. The distance is zero (closest representable) for 3[super 3] = 27
  56. but `float_distance(r.first, r.second) = 3` for cube root of 28 with this function.
  57. The result (avoiding overflow) is midway between these two values.
  58. [h3:cbrt_1st_derivative Cube root function with 1st derivative (slope)]
  59. We now solve the same problem, but using more information about the function,
  60. to show how this can speed up finding the best estimate of the root.
  61. For the root function, the 1st differential (the slope of the tangent to a curve at any point) is known.
  62. This algorithm is similar to this [@http://en.wikipedia.org/wiki/Nth_root_algorithm nth root algorithm].
  63. If you need some reminders, then
  64. [@http://en.wikipedia.org/wiki/Derivative#Derivatives_of_elementary_functions derivatives of elementary functions]
  65. may help.
  66. Using the rule that the derivative of ['x[super n]] for positive n (actually all nonzero n) is ['n x[super n-1]],
  67. allows us to get the 1st differential as ['3x[super 2]].
  68. To see how this extra information is used to find a root, view
  69. [@http://en.wikipedia.org/wiki/Newton%27s_method Newton-Raphson iterations]
  70. and the [@http://en.wikipedia.org/wiki/Newton%27s_method#mediaviewer/File:NewtonIteration_Ani.gif animation].
  71. We define a better functor `cbrt_functor_deriv` that returns
  72. both the evaluation of the function to solve, along with its first derivative:
  73. To '['return]' two values, we use a [@http://en.cppreference.com/w/cpp/utility/pair std::pair]
  74. of floating-point values.
  75. [root_finding_1_deriv_1]
  76. The result of [@boost:/libs/math/include/boost/math/tools/roots.hpp `newton_raphson_iterate`]
  77. function is a single value.
  78. [tip There is a compromise between accuracy and speed when chosing the value of `digits`.
  79. It is tempting to simply chose `std::numeric_limits<T>::digits`,
  80. but this may mean some inefficient and unnecessary iterations as the function thrashes around
  81. trying to locate the last bit. In theory, since the precision doubles with each step
  82. it is sufficient to stop when half the bits are correct: as the last step will have doubled
  83. that to full precision. Of course the function has no way to tell if that is actually the case
  84. unless it does one more step to be sure. In practice setting the precision to slightly more
  85. than `std::numeric_limits<T>::digits / 2` is a good choice.]
  86. Note that it is up to the caller of the function to check the iteration count
  87. after the call to see if iteration stoped as a result of running out of iterations
  88. rather than meeting the required precision.
  89. Using the test data in [@../../test/test_cbrt.cpp /test/test_cbrt.cpp] this found the cube root
  90. exact to the last digit in every case, and in no more than 6 iterations at double
  91. precision. However, you will note that a high precision was used in this
  92. example, exactly what was warned against earlier on in these docs! In this
  93. particular case it is possible to compute ['f(x)] exactly and without undue
  94. cancellation error, so a high limit is not too much of an issue.
  95. However, reducing the limit to `std::numeric_limits<T>::digits * 2 / 3` gave full
  96. precision in all but one of the test cases (and that one was out by just one bit).
  97. The maximum number of iterations remained 6, but in most cases was reduced by one.
  98. Note also that the above code omits a probable optimization by computing z[sup2]
  99. and reusing it, omits error handling, and does not handle
  100. negative values of z correctly. (These are left as the customary exercise for the reader!)
  101. The `boost::math::cbrt` function also includes these and other improvements:
  102. most importantly it uses a much better initial guess which reduces the iteration count to
  103. just 1 in almost all cases.
  104. [h3:cbrt_2_derivatives Cube root with 1st & 2nd derivative (slope & curvature)]
  105. Next we define yet another even better functor `cbrt_functor_2deriv` that returns
  106. both the evaluation of the function to solve,
  107. along with its first [*and second] derivative:
  108. [expression ['f''(x) = 6x]]
  109. using information about both slope and curvature to speed convergence.
  110. To [''return'] three values, we use a `tuple` of three floating-point values:
  111. [root_finding_2deriv_1]
  112. The function `halley_iterate` also returns a single value,
  113. and the number of iterations will reveal if it met the convergence criterion set by `get_digits`.
  114. The no-derivative method gives a result of
  115. cbrt_noderiv(28) = 3.0365889718756618
  116. with a 3 bits distance between the bracketed values, whereas the derivative methods both converge to a single value
  117. cbrt_2deriv(28) = 3.0365889718756627
  118. which we can compare with the [@boost:/libs/math/doc/html/math_toolkit/powers/cbrt.html boost::math::cbrt]
  119. cbrt(28) = 3.0365889718756627
  120. Note that the iterations are set to stop at just one-half of full precision,
  121. and yet, even so, not one of the test cases had a single bit wrong.
  122. What's more, the maximum number of iterations was now just 4.
  123. Just to complete the picture, we could have called
  124. [link math_toolkit.roots_deriv.schroder `schroder_iterate`] in the last
  125. example: and in fact it makes no difference to the accuracy or number of iterations
  126. in this particular case. However, the relative performance of these two methods
  127. may vary depending upon the nature of ['f(x)], and the accuracy to which the initial
  128. guess can be computed. There appear to be no generalisations that can be made
  129. except "try them and see".
  130. Finally, had we called `cbrt` with [@http://shoup.net/ntl/doc/RR.txt NTL::RR]
  131. set to 1000 bit precision (about 300 decimal digits),
  132. then full precision can be obtained with just 7 iterations.
  133. To put that in perspective,
  134. an increase in precision by a factor of 20, has less than doubled the number of
  135. iterations. That just goes to emphasise that most of the iterations are used
  136. up getting the first few digits correct: after that these methods can churn out
  137. further digits with remarkable efficiency.
  138. Or to put it another way: ['nothing beats a really good initial guess!]
  139. Full code of this example is at
  140. [@../../example/root_finding_example.cpp root_finding_example.cpp],
  141. [endsect] [/section:cbrt_eg Finding the Cubed Root With and Without Derivatives]
  142. [section:lambda Using C++11 Lambda's]
  143. Since all the root finding functions accept a function-object, they can be made to
  144. work (often in a lot less code) with C++11 lambda's. Here's the much reduced code for our "toy" cube root function:
  145. [root_finding_2deriv_lambda]
  146. Full code of this example is at
  147. [@../../example/root_finding_example.cpp root_finding_example.cpp],
  148. [endsect] [/section:lambda Using C++11 Lambda's]
  149. [section:5th_root_eg Computing the Fifth Root]
  150. Let's now suppose we want to find the [*fifth root] of a number ['a].
  151. The equation we want to solve is :
  152. [expression ['f](x) = ['x[super 5] -a]]
  153. If your differentiation is a little rusty
  154. (or you are faced with an function whose complexity makes differentiation daunting),
  155. then you can get help, for example, from the invaluable
  156. [@http://www.wolframalpha.com/ WolframAlpha site.]
  157. For example, entering the commmand: `differentiate x ^ 5`
  158. or the Wolfram Language command: ` D[x ^ 5, x]`
  159. gives the output: `d/dx(x ^ 5) = 5 x ^ 4`
  160. and to get the second differential, enter: `second differentiate x ^ 5`
  161. or the Wolfram Language command: `D[x ^ 5, { x, 2 }]`
  162. to get the output: `d ^ 2 / dx ^ 2(x ^ 5) = 20 x ^ 3`
  163. To get a reference value, we can enter: [^fifth root 3126]
  164. or: `N[3126 ^ (1 / 5), 50]`
  165. to get a result with a precision of 50 decimal digits:
  166. 5.0003199590478625588206333405631053401128722314376
  167. (We could also get a reference value using __multiprecision_root).
  168. The 1st and 2nd derivatives of ['x[super 5]] are:
  169. [expression ['f\'(x) = 5x[super 4]]]
  170. [expression ['f\'\'(x) = 20x[super 3]]]
  171. [root_finding_fifth_functor_2deriv]
  172. [root_finding_fifth_2deriv]
  173. Full code of this example is at
  174. [@../../example/root_finding_example.cpp root_finding_example.cpp] and
  175. [@../../example/root_finding_n_example.cpp root_finding_n_example.cpp].
  176. [endsect] [/section:5th_root_eg Computing the Fifth Root]
  177. [section:multiprecision_root Root-finding using Boost.Multiprecision]
  178. The apocryphally astute reader might, by now, be asking "How do we know if this computes the 'right' answer?".
  179. For most values, there is, sadly, no 'right' answer.
  180. This is because values can only rarely be ['exactly represented] by C++ floating-point types.
  181. What we do want is the 'best' representation - one that is the nearest __representable value.
  182. (For more about how numbers are represented see __floating_point).
  183. Of course, we might start with finding an external reference source like
  184. __WolframAlpha, as above, but this is not always possible.
  185. Another way to reassure is to compute 'reference' values at higher precision
  186. with which to compare the results of our iterative computations using built-in like `double`.
  187. They should agree within the tolerance that was set.
  188. The result of `static_cast`ing to `double` from a higher-precision type like `cpp_bin_float_50` is guaranteed
  189. to be the [*nearest representable] `double` value.
  190. For example, the cube root functions in our example for `cbrt(28.)` compute
  191. `std::cbrt<double>(28.) = 3.0365889718756627`
  192. WolframAlpha says `3.036588971875662519420809578505669635581453977248111123242141...`
  193. `static_cast<double>(3.03658897187566251942080957850) = 3.0365889718756627`
  194. This example `cbrt(28.) = 3.0365889718756627`
  195. [tip To ensure that all potentially significant decimal digits are displayed use `std::numeric_limits<T>::max_digits10`
  196. (or if not available on older platforms or compilers use `2+std::numeric_limits<double>::digits*3010/10000`).[br]
  197. Ideally, values should agree to `std::numeric-limits<T>::digits10` decimal digits.
  198. This also means that a 'reference' value to be [*input] or `static_cast` should have
  199. at least `max_digits10` decimal digits (17 for 64-bit `double`).
  200. ]
  201. If we wish to compute [*higher-precision values] then, on some platforms, we may be able to use `long double`
  202. with a higher precision than `double` to compare with the very common `double`
  203. and/or a more efficient built-in quad floating-point type like `__float128`.
  204. Almost all platforms can easily use __multiprecision,
  205. for example, __cpp_dec_float or a binary type __cpp_bin_float types,
  206. to compute values at very much higher precision.
  207. [note With multiprecision types, it is debatable whether to use the type `T` for computing the initial guesses.
  208. Type `double` is like to be accurate enough for the method used in these examples.
  209. This would limit the exponent range of possible values to that of `double`.
  210. There is also the cost of conversion to and from type `T` to consider.
  211. In these examples, `double` is used via `typedef double guess_type`.]
  212. Since the functors and functions used above are templated on the value type,
  213. we can very simply use them with any of the __multiprecision types. As a reminder,
  214. here's our toy cube root function using 2 derivatives and C++11 lambda functions to find the root:
  215. [root_finding_2deriv_lambda]
  216. Some examples below are 50 decimal digit decimal and binary types
  217. (and on some platforms a much faster `float128` or `quad_float` type )
  218. that we can use with these includes:
  219. [root_finding_multiprecision_include_1]
  220. Some using statements simplify their use:
  221. [root_finding_multiprecision_example_1]
  222. They can be used thus:
  223. [root_finding_multiprecision_example_2]
  224. A reference value computed by __WolframAlpha is
  225. N[2^(1/3), 50] 1.2599210498948731647672106072782283505702514647015
  226. which agrees exactly.
  227. To [*show] values to their full precision, it is necessary to adjust the `std::ostream` `precision` to suit the type, for example:
  228. [root_finding_multiprecision_show_1]
  229. [root_finding_multiprecision_example_3]
  230. which outputs:
  231. [pre
  232. cbrt(2) = 1.2599210498948731647672106072782283505702514647015
  233. value = 2, cube root =1.25992104989487
  234. value = 2, cube root =1.25992104989487
  235. value = 2, cube root =1.2599210498948731647672106072782283505702514647015
  236. ]
  237. [tip Be [*very careful] about the floating-point type `T` that is passed to the root-finding function.
  238. Carelessly passing a integer by writing
  239. `cpp_dec_float_50 r = cbrt_2deriv(2);` or `show_cube_root(2);`
  240. will provoke many warnings and compile errors.
  241. Even `show_cube_root(2.F);` will produce warnings because `typedef double guess_type` defines the type
  242. used to compute the guess and bracket values as `double`.
  243. Even more treacherous is passing a `double` as in `cpp_dec_float_50 r = cbrt_2deriv(2.);`
  244. which silently gives the 'wrong' result, computing a `double` result and [*then] converting to `cpp_dec_float_50`!
  245. All digits beyond `max_digits10` will be incorrect.
  246. Making the `cbrt` type explicit with `cbrt_2deriv<cpp_dec_float_50>(2.);` will give you the desired 50 decimal digit precision result.
  247. ] [/tip]
  248. Full code of this example is at
  249. [@../../example/root_finding_multiprecision_example.cpp root_finding_multiprecision_example.cpp].
  250. [endsect] [/section:multiprecision_root Root-finding using Boost.Multiprecision]
  251. [section:nth_root Generalizing to Compute the nth root]
  252. If desired, we can now further generalize to compute the ['n]th root by computing the derivatives [*at compile-time]
  253. using the rules for differentiation and `boost::math::pow<N>`
  254. where template parameter `N` is an integer and a compile time constant. Our functor and function now have an additional template parameter `N`,
  255. for the root required.
  256. [note Since the powers and derivatives are fixed at compile time, the resulting code is as efficient as as if hand-coded as the cube and fifth-root examples above.
  257. A good compiler should also optimise any repeated multiplications.]
  258. Our ['n]th root functor is
  259. [root_finding_nth_functor_2deriv]
  260. and our ['n]th root function is
  261. [root_finding_nth_function_2deriv]
  262. [root_finding_n_example_2]
  263. produces an output similar to this
  264. [root_finding_example_output_1]
  265. [tip Take care with the type passed to the function. It is best to pass a `double` or greater-precision floating-point type.
  266. Passing an integer value, for example, `nth_2deriv<5>(2)` will be rejected, while `nth_2deriv<5, double>(2)` converts the integer to `double`.
  267. Avoid passing a `float` value that will provoke warnings (actually spurious) from the compiler about potential loss of data,
  268. as noted above.]
  269. [warning Asking for unreasonable roots, for example, `show_nth_root<1000000>(2.);` may lead to
  270. [@http://en.wikipedia.org/wiki/Loss_of_significance Loss of significance] like
  271. `Type double value = 2, 1000000th root = 1.00000069314783`.
  272. Use of the the `pow` function is more sensible for this unusual need.
  273. ]
  274. Full code of this example is at
  275. [@../../example/root_finding_n_example.cpp root_finding_n_example.cpp].
  276. [endsect]
  277. [section:elliptic_eg A More complex example - Inverting the Elliptic Integrals]
  278. The arc length of an ellipse with radii ['a] and ['b] is given by:
  279. [pre L(a, b) = 4aE(k)]
  280. with:
  281. [pre k = [sqrt](1 - b[super 2]/a[super 2])]
  282. where ['E(k)] is the complete elliptic integral of the second kind - see __ellint_2.
  283. Let's suppose we know the arc length and one radii, we can then calculate the other
  284. radius by inverting the formula above. We'll begin by encoding the above formula
  285. into a functor that our root-finding algorithms can call.
  286. Note that while not
  287. completely obvious from the formula above, the function is completely symmetrical
  288. in the two radii - which can be interchanged at will - in this case we need to
  289. make sure that `a >= b` so that we don't accidentally take the square root of a negative number:
  290. [import ../../example/root_elliptic_finding.cpp]
  291. [elliptic_noderv_func]
  292. We'll also need a decent estimate to start searching from, the approximation:
  293. [pre L(a, b) [approx] 4[sqrt](a[super 2] + b[super 2])]
  294. Is easily inverted to give us what we need, which using derivative-free root
  295. finding leads to the algorithm:
  296. [elliptic_root_noderiv]
  297. This function generally finds the root within 8-10 iterations, so given that the runtime
  298. is completely dominated by the cost of calling the ellliptic integral it would be nice to
  299. reduce that count somewhat. We'll try to do that by using a derivative-based method;
  300. the derivatives of this function are rather hard to work out by hand, but fortunately
  301. [@http://www.wolframalpha.com/input/?i=d%2Fda+\[4+*+a+*+EllipticE%281+-+b^2%2Fa^2%29\]
  302. Wolfram Alpha] can do the grunt work for us to give:
  303. [pre d/da L(a, b) = 4(a[super 2]E(k) - b[super 2]K(k)) / (a[super 2] - b[super 2])]
  304. Note that now we have [*two] elliptic integral calls to get the derivative, so our
  305. functor will be at least twice as expensive to call as the derivative-free one above:
  306. we'll have to reduce the iteration count quite substantially to make a difference!
  307. Here's the revised functor:
  308. [elliptic_1deriv_func]
  309. The root-finding code is now almost the same as before, but we'll make use of
  310. Newton-iteration to get the result:
  311. [elliptic_1deriv]
  312. The number of iterations required for `double` precision is now usually around 4 -
  313. so we've slightly more than halved the number of iterations, but made the
  314. functor twice as expensive to call!
  315. Interestingly though, the second derivative requires no more expensive
  316. elliptic integral calls than the first does, in other words it comes
  317. essentially "for free", in which case we might as well make use of it
  318. and use Halley-iteration. This is quite a typical situation when
  319. inverting special-functions. Here's the revised functor:
  320. [elliptic_2deriv_func]
  321. The actual root-finding code is almost the same as before, except we can
  322. use Halley, rather than Newton iteration:
  323. [elliptic_2deriv]
  324. While this function uses only slightly fewer iterations (typically around 3)
  325. to find the root, compared to the original derivative-free method, we've moved from
  326. 8-10 elliptic integral calls to 6.
  327. Full code of this example is at
  328. [@../../example/root_elliptic_finding.cpp root_elliptic_finding.cpp].
  329. [endsect]
  330. [endsect] [/section:root_examples Examples of Root Finding (with and without derivatives)]
  331. [section:bad_guess The Effect of a Poor Initial Guess]
  332. It's instructive to take our "toy" example algorithms, and use deliberately bad initial guesses to see how the
  333. various root finding algorithms fair. We'll start with the cubed root, and using the cube root of 500 as the test case:
  334. [table
  335. [[Initial Guess=][-500% ([approx]1.323)][-100% ([approx]3.97)][-50% ([approx]3.96)][-20% ([approx]6.35)][-10% ([approx]7.14)][-5% ([approx]7.54)][5% ([approx]8.33)][10% ([approx]8.73)][20% ([approx]9.52)][50% ([approx]11.91)][100% ([approx]15.87)][500 ([approx]47.6)]]
  336. [[bracket_and_solve_root][12][8][8][10][11][11][11][11][11][11][7][13]]
  337. [[newton_iterate][12][7][7][5][5][4][4][5][5][6][7][9]]
  338. [[halley_iterate][7][4][4][3][3][3][3][3][3][4][4][6]]
  339. [[schroder_iterate][11][6][6][4][3][3][3][3][4][5][5][8]]
  340. ]
  341. As you can see `bracket_and_solve_root` is relatively insensitive to starting location - as long as you don't start many orders of magnitude away from the root it will
  342. take roughly the same number of steps to bracket the root and solve it. On the other hand the derivative-based methods are slow to start, but once they have some digits
  343. correct they increase precision exceptionally fast: they are therefore quite sensitive to the initial starting location.
  344. The next table shows the number of iterations required to find the second radius of an ellipse with first radius 50 and arc-length 500:
  345. [table
  346. [[Initial Guess=][-500% ([approx]20.6)][-100% ([approx]61.81)][-50% ([approx]61.81)][-20% ([approx]98.9)][-10% ([approx]111.3)][-5% ([approx]117.4)][5% ([approx]129.8)][10% ([approx]136)][20% ([approx]148.3)][50% ([approx]185.4)][100% ([approx]247.2)][500 ([approx]741.7)]]
  347. [[bracket_and_solve_root][11][5][5][8][8][7][7][8][9][8][6][10]]
  348. [[newton_iterate][4][4][4][3][3][3][3][3][3][4][4][4]]
  349. [[halley_iterate][4][3][3][3][3][2][2][3][3][3][3][3]]
  350. [[schroder_iterate][4][3][3][3][3][2][2][3][3][3][3][3]]
  351. ]
  352. Interestingly this function is much more resistant to a poor initial guess when using derivatives.
  353. [endsect]
  354. [section:bad_roots Examples Where Root Finding Goes Wrong]
  355. There are many reasons why root root finding can fail, here are just a few of the more common examples:
  356. [h3 Local Minima]
  357. If you start in the wrong place, such as z[sub 0] here:
  358. [$../roots/bad_root_1.svg]
  359. Then almost any root-finding algorithm will descend into a local minima rather than find the root.
  360. [h3 Flatlining]
  361. In this example, we're starting from a location (z[sub 0]) where the first derivative is essentially zero:
  362. [$../roots/bad_root_2.svg]
  363. In this situation the next iteration will shoot off to infinity (assuming we're using derivatives that is). Our
  364. code guards against this by insisting that the root is always bracketed, and then never stepping outside those bounds.
  365. In a case like this, no root finding algorithm can do better than bisecting until the root is found.
  366. Note that there is no scale on the graph, we have seen examples of this situation occur in practice ['even when
  367. several decimal places of the initial guess z[sub 0] are correct.]
  368. This is really a special case of a more common situation where root finding with derivatives is ['divergent]. Consider
  369. starting at z[sub 0] in this case:
  370. [$../roots/bad_root_4.svg]
  371. An initial Newton step would take you further from the root than you started, as will all subsequent steps.
  372. [h3 Micro-stepping / Non-convergence]
  373. Consider starting at z[sub 0] in this situation:
  374. [$../roots/bad_root_3.svg]
  375. The first derivative is essentially infinite, and the second close to zero (and so offers no correction if we use it),
  376. as a result we take a very small first step. In the worst case situation, the first step is so small
  377. - perhaps even so small that subtracting from z[sub 0] has no effect at the current working precision - that our algorithm
  378. will assume we are at the root already and terminate. Otherwise we will take lot's of very small steps which never converge
  379. on the root: our algorithms will protect against that by reverting to bisection.
  380. An example of this situation would be trying to find the root of e[super -1/z[super 2]] - this function has a single
  381. root at ['z = 0], but for ['z[sub 0] < 0] neither Newton nor Halley steps will ever converge on the root, and for ['z[sub 0] > 0]
  382. the steps are actually divergent.
  383. [endsect]
  384. [/
  385. Copyright 2015 John Maddock and Paul A. Bristow.
  386. Distributed under the Boost Software License, Version 1.0.
  387. (See accompanying file LICENSE_1_0.txt or copy at
  388. http://www.boost.org/LICENSE_1_0.txt).
  389. ]