]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/math/example/root_finding_fifth.cpp
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / boost / libs / math / example / root_finding_fifth.cpp
CommitLineData
7c673cae
FG
1// root_finding_fith.cpp
2
3// Copyright Paul A. Bristow 2014.
4
5// Use, modification and distribution are subject to the
6// Boost Software License, Version 1.0.
7// (See accompanying file LICENSE_1_0.txt
8// or copy at http://www.boost.org/LICENSE_1_0.txt)
9
10// Example of finding fifth root using Newton-Raphson, Halley, Schroder, TOMS748 .
11
12// Note that this file contains Quickbook mark-up as well as code
13// and comments, don't change any of the special comment mark-ups!
14
15// To get (copious!) diagnostic output, add make this define here or elsewhere.
16//#define BOOST_MATH_INSTRUMENT
17
18
19//[root_fifth_headers
20/*
21This example demonstrates how to use the Boost.Math tools for root finding,
22taking the fifth root function (fifth_root) as an example.
23It shows how use of derivatives can improve the speed.
24
25First some includes that will be needed.
26Using statements are provided to list what functions are being used in this example:
27you can of course qualify the names in other ways.
28*/
29
30#include <boost/math/tools/roots.hpp>
31using boost::math::policies::policy;
32using boost::math::tools::newton_raphson_iterate;
33using boost::math::tools::halley_iterate;
34using boost::math::tools::eps_tolerance; // Binary functor for specified number of bits.
35using boost::math::tools::bracket_and_solve_root;
36using boost::math::tools::toms748_solve;
37
38#include <boost/math/special_functions/next.hpp>
39
40#include <tuple>
41#include <utility> // pair, make_pair
42
43//] [/root_finding_headers]
44
45#include <iostream>
46using std::cout; using std::endl;
47#include <iomanip>
48using std::setw; using std::setprecision;
49#include <limits>
50using std::numeric_limits;
51
52/*
53//[root_finding_fifth_1
54Let's suppose we want to find the fifth root of a number.
55
56The equation we want to solve is:
57
58__spaces ['f](x) = x[fifth]
59
60We will first solve this without using any information
61about the slope or curvature of the fifth function.
62
63If your differentiation is a little rusty
64(or you are faced with an equation whose complexity is daunting,
65then you can get help, for example from the invaluable
66
67http://www.wolframalpha.com/ site
68
f67539c2 69entering the command
7c673cae
FG
70
71 differentiate x^5
72
73or the Wolfram Language command
74
75 D[x^5, x]
76
77gives the output
78
79 d/dx(x^5) = 5 x^4
80
81and to get the second differential, enter
82
83 second differentiate x^5
84
85or the Wolfram Language
86
87 D[x^5, {x, 2}]
88
89to get the output
90
91 d^2/dx^2(x^5) = 20 x^3
92
93or
94
95 20 x^3
96
97To get a reference value we can enter
98
99 fifth root 3126
100
101or
102
103 N[3126^(1/5), 50]
104
105to get a result with a precision of 50 decimal digits
106
107 5.0003199590478625588206333405631053401128722314376
108
109(We could also get a reference value using Boost.Multiprecision).
110
111We then show how adding what we can know, for this function, about the slope,
112the 1st derivation /f'(x)/, will speed homing in on the solution,
113and then finally how adding the curvature /f''(x)/ as well will improve even more.
114
115The 1st and 2nd derivatives of x[fifth] are:
116
117__spaces ['f]\'(x) = 2x[sup2]
118
119__spaces ['f]\'\'(x) = 6x
120
121*/
122
123//] [/root_finding_fifth_1]
124
125//[root_finding_fifth_functor_noderiv
126
127template <class T>
128struct fifth_functor_noderiv
129{ // fifth root of x using only function - no derivatives.
130 fifth_functor_noderiv(T const& to_find_root_of) : value(to_find_root_of)
131 { // Constructor stores value to find root of.
132 // For example: calling fifth_functor<T>(x) to get fifth root of x.
133 }
134 T operator()(T const& x)
135 { //! \returns f(x) - value.
136 T fx = x*x*x*x*x - value; // Difference (estimate x^5 - value).
137 return fx;
138 }
139private:
140 T value; // to be 'fifth_rooted'.
141};
142
143//] [/root_finding_fifth_functor_noderiv]
144
145//cout << ", std::numeric_limits<" << typeid(T).name() << ">::digits = " << digits
146// << ", accuracy " << get_digits << " bits."<< endl;
147
148
149/*`Implementing the fifth root function itself is fairly trivial now:
150the hardest part is finding a good approximation to begin with.
151In this case we'll just divide the exponent by five.
152(There are better but more complex guess algorithms used in 'real-life'.)
153
154fifth root function is 'Really Well Behaved' in that it is monotonic
155and has only one root
156(we leave negative values 'as an exercise for the student').
157*/
158
159//[root_finding_fifth_noderiv
160
161template <class T>
162T fifth_noderiv(T x)
163{ //! \returns fifth root of x using bracket_and_solve (no derivatives).
164 using namespace std; // Help ADL of std functions.
165 using namespace boost::math::tools; // For bracket_and_solve_root.
166
167 int exponent;
168 frexp(x, &exponent); // Get exponent of z (ignore mantissa).
169 T guess = ldexp(1., exponent / 5); // Rough guess is to divide the exponent by five.
170 T factor = 2; // To multiply and divide guess to bracket.
171 // digits used to control how accurate to try to make the result.
172 // int digits = 3 * std::numeric_limits<T>::digits / 4; // 3/4 maximum possible binary digits accuracy for type T.
173 int digits = std::numeric_limits<T>::digits; // Maximum possible binary digits accuracy for type T.
174
175 //boost::uintmax_t maxit = (std::numeric_limits<boost::uintmax_t>::max)();
176 // (std::numeric_limits<boost::uintmax_t>::max)() = 18446744073709551615
177 // which is more than anyone might wish to wait for!!!
178 // so better to choose some reasonable estimate of how many iterations may be needed.
179
180 const boost::uintmax_t maxit = 50; // Chosen max iterations,
181 // but updated on exit with actual iteration count.
182
183 // We could also have used a maximum iterations provided by any policy:
184 // boost::uintmax_t max_it = policies::get_max_root_iterations<Policy>();
185
f67539c2 186 boost::uintmax_t it = maxit; // Initially our chosen max iterations,
7c673cae
FG
187
188 bool is_rising = true; // So if result if guess^5 is too low, try increasing guess.
189 eps_tolerance<double> tol(digits);
190 std::pair<T, T> r =
191 bracket_and_solve_root(fifth_functor_noderiv<T>(x), guess, factor, is_rising, tol, it);
192 // because the iteration count is updating,
193 // you can't call with a literal maximum iterations value thus:
194 //bracket_and_solve_root(fifth_functor_noderiv<T>(x), guess, factor, is_rising, tol, 20);
195
196 // Can show how many iterations (this information is lost outside fifth_noderiv).
197 cout << "Iterations " << it << endl;
198 if (it >= maxit)
199 { // Failed to converge (or is jumping between bracket values).
200 cout << "Unable to locate solution in chosen iterations:"
201 " Current best guess is between " << r.first << " and " << r.second << endl;
202 }
203 T distance = float_distance(r.first, r.second);
204 if (distance > 0)
205 { //
206 std::cout << distance << " bits separate the bracketing values." << std::endl;
207 for (int i = 0; i < distance; i++)
208 { // Show all the values within the bracketing values.
209 std::cout << float_advance(r.first, i) << std::endl;
210 }
211 }
212 else
213 { // distance == 0 and r.second == r.first
214 std::cout << "Converged to a single value " << r.first << std::endl;
215 }
216
217 return r.first + (r.second - r.first) / 2; // return midway between bracketed interval.
218} // T fifth_noderiv(T x)
219
220//] [/root_finding_fifth_noderiv]
221
222
223
224// maxit = 10
225// Unable to locate solution in chosen iterations: Current best guess is between 3.0365889718756613 and 3.0365889718756627
226
227
228/*`
229We now solve the same problem, but using more information about the function,
230to show how this can speed up finding the best estimate of the root.
231
232For this function, the 1st differential (the slope of the tangent to a curve at any point) is known.
233
234[@http://en.wikipedia.org/wiki/Derivative#Derivatives_of_elementary_functions Derivatives]
235gives some reminders.
236
237Using the rule that the derivative of x^n for positive n (actually all nonzero n) is nx^n-1,
238allows use to get the 1st differential as 3x^2.
239
240To see how this extra information is used to find the root, view this demo:
241[@http://en.wikipedia.org/wiki/Newton%27s_methodNewton Newton-Raphson iterations].
242
243We need to define a different functor that returns
244both the evaluation of the function to solve, along with its first derivative:
245
246To \'return\' two values, we use a pair of floating-point values:
247*/
248
249//[root_finding_fifth_functor_1stderiv
250
251template <class T>
252struct fifth_functor_1stderiv
253{ // Functor returning function and 1st derivative.
254
255 fifth_functor_1stderiv(T const& target) : value(target)
256 { // Constructor stores the value to be 'fifth_rooted'.
257 }
258
259 std::pair<T, T> operator()(T const& z) // z is best estimate so far.
260 { // Return both f(x) and first derivative f'(x).
261 T fx = z*z*z*z*z - value; // Difference estimate fx = x^5 - value.
262 T d1x = 5 * z*z*z*z; // 1st derivative d1x = 5x^4.
263 return std::make_pair(fx, d1x); // 'return' both fx and d1x.
264 }
265private:
266 T value; // to be 'fifth_rooted'.
267}; // fifth_functor_1stderiv
268
269//] [/root_finding_fifth_functor_1stderiv]
270
271
272/*`Our fifth root function using fifth_functor_1stderiv is now:*/
273
274//[root_finding_fifth_1deriv
275
276template <class T>
277T fifth_1deriv(T x)
278{ //! \return fifth root of x using 1st derivative and Newton_Raphson.
279 using namespace std; // For frexp, ldexp, numeric_limits.
280 using namespace boost::math::tools; // For newton_raphson_iterate.
281
282 int exponent;
283 frexp(x, &exponent); // Get exponent of x (ignore mantissa).
284 T guess = ldexp(1., exponent / 5); // Rough guess is to divide the exponent by three.
285 // Set an initial bracket interval.
286 T min = ldexp(0.5, exponent / 5); // Minimum possible value is half our guess.
287 T max = ldexp(2., exponent / 5);// Maximum possible value is twice our guess.
288
289 // digits used to control how accurate to try to make the result.
290 int digits = std::numeric_limits<T>::digits; // Maximum possible binary digits accuracy for type T.
291
292 const boost::uintmax_t maxit = 20; // Optionally limit the number of iterations.
293 boost::uintmax_t it = maxit; // limit the number of iterations.
294 //cout << "Max Iterations " << maxit << endl; //
295 T result = newton_raphson_iterate(fifth_functor_1stderiv<T>(x), guess, min, max, digits, it);
296 // Can check and show how many iterations (updated by newton_raphson_iterate).
297 cout << it << " iterations (from max of " << maxit << ")" << endl;
298 return result;
299} // fifth_1deriv
300
301//] [/root_finding_fifth_1deriv]
302
303// int get_digits = (digits * 2) /3; // Two thirds of maximum possible accuracy.
304
305//boost::uintmax_t maxit = (std::numeric_limits<boost::uintmax_t>::max)();
306// the default (std::numeric_limits<boost::uintmax_t>::max)() = 18446744073709551615
307// which is more than we might wish to wait for!!! so we can reduce it
308
309/*`
310Finally need to define yet another functor that returns
311both the evaluation of the function to solve,
312along with its first and second derivatives:
313
314f''(x) = 3 * 3x
315
316To \'return\' three values, we use a tuple of three floating-point values:
317*/
318
319//[root_finding_fifth_functor_2deriv
320
321template <class T>
322struct fifth_functor_2deriv
323{ // Functor returning both 1st and 2nd derivatives.
324 fifth_functor_2deriv(T const& to_find_root_of) : value(to_find_root_of)
325 { // Constructor stores value to find root of, for example:
326 }
327
328 // using boost::math::tuple; // to return three values.
329 std::tuple<T, T, T> operator()(T const& x)
330 { // Return both f(x) and f'(x) and f''(x).
331 T fx = x*x*x*x*x - value; // Difference (estimate x^3 - value).
332 T dx = 5 * x*x*x*x; // 1st derivative = 5x^4.
333 T d2x = 20 * x*x*x; // 2nd derivative = 20 x^3
334 return std::make_tuple(fx, dx, d2x); // 'return' fx, dx and d2x.
335 }
336private:
337 T value; // to be 'fifth_rooted'.
338}; // struct fifth_functor_2deriv
339
340//] [/root_finding_fifth_functor_2deriv]
341
342
343/*`Our fifth function is now:*/
344
345//[root_finding_fifth_2deriv
346
347template <class T>
348T fifth_2deriv(T x)
349{ // return fifth root of x using 1st and 2nd derivatives and Halley.
350 using namespace std; // Help ADL of std functions.
351 using namespace boost::math; // halley_iterate
352
353 int exponent;
354 frexp(x, &exponent); // Get exponent of z (ignore mantissa).
355 T guess = ldexp(1., exponent / 5); // Rough guess is to divide the exponent by three.
356 T min = ldexp(0.5, exponent / 5); // Minimum possible value is half our guess.
357 T max = ldexp(2., exponent / 5); // Maximum possible value is twice our guess.
358
359 int digits = std::numeric_limits<T>::digits / 2; // Half maximum possible binary digits accuracy for type T.
360 const boost::uintmax_t maxit = 50;
361 boost::uintmax_t it = maxit;
362 T result = halley_iterate(fifth_functor_2deriv<T>(x), guess, min, max, digits, it);
363 // Can show how many iterations (updated by halley_iterate).
364 cout << it << " iterations (from max of " << maxit << ")" << endl;
365
366 return result;
367} // fifth_2deriv(x)
368
369//] [/root_finding_fifth_2deriv]
370
371int main()
372{
373
374 //[root_finding_example_1
375 cout << "fifth Root finding (fifth) Example." << endl;
376 // Show all possibly significant decimal digits.
377 cout.precision(std::numeric_limits<double>::max_digits10);
378 // or use cout.precision(max_digits10 = 2 + std::numeric_limits<double>::digits * 3010/10000);
379 try
380 { // Always use try'n'catch blocks with Boost.Math to get any error messages.
381
382 double v27 = 3125; // Example of a value that has an exact integer fifth root.
383 // exact value of fifth root is exactly 5.
384
385 std::cout << "Fifth root of " << v27 << " is " << 5 << std::endl;
386
387 double v28 = v27+1; // Example of a value whose fifth root is *not* exactly representable.
388 // Value of fifth root is 5.0003199590478625588206333405631053401128722314376 (50 decimal digits precision)
389 // and to std::numeric_limits<double>::max_digits10 double precision (usually 17) is
390
391 double root5v2 = static_cast<double>(5.0003199590478625588206333405631053401128722314376);
392
393 std::cout << "Fifth root of " << v28 << " is " << root5v2 << std::endl;
394
395 // Using bracketing:
396 double r = fifth_noderiv(v27);
397 cout << "fifth_noderiv(" << v27 << ") = " << r << endl;
398
399 r = fifth_noderiv(v28);
400 cout << "fifth_noderiv(" << v28 << ") = " << r << endl;
401
402 // Using 1st differential Newton-Raphson:
403 r = fifth_1deriv(v27);
404 cout << "fifth_1deriv(" << v27 << ") = " << r << endl;
405 r = fifth_1deriv(v28);
406 cout << "fifth_1deriv(" << v28 << ") = " << r << endl;
407
408 // Using Halley with 1st and 2nd differentials.
409 r = fifth_2deriv(v27);
410 cout << "fifth_2deriv(" << v27 << ") = " << r << endl;
411 r = fifth_2deriv(v28);
412 cout << "fifth_2deriv(" << v28 << ") = " << r << endl;
413 }
414 catch (const std::exception& e)
415 { // Always useful to include try & catch blocks because default policies
416 // are to throw exceptions on arguments that cause errors like underflow, overflow.
417 // Lacking try & catch blocks, the program will abort without a message below,
418 // which may give some helpful clues as to the cause of the exception.
419 std::cout <<
420 "\n""Message from thrown exception was:\n " << e.what() << std::endl;
421 }
422 //] [/root_finding_example_1
423 return 0;
424} // int main()
425
426//[root_finding_example_output
427/*`
428Normal output is:
429
430[pre
4311> Description: Autorun "J:\Cpp\MathToolkit\test\Math_test\Release\root_finding_fifth.exe"
4321> fifth Root finding (fifth) Example.
4331> Fifth root of 3125 is 5
4341> Fifth root of 3126 is 5.0003199590478626
4351> Iterations 10
4361> Converged to a single value 5
4371> fifth_noderiv(3125) = 5
4381> Iterations 11
4391> 2 bits separate the bracketing values.
4401> 5.0003199590478609
4411> 5.0003199590478618
4421> fifth_noderiv(3126) = 5.0003199590478618
4431> 6 iterations (from max of 20)
4441> fifth_1deriv(3125) = 5
4451> 7 iterations (from max of 20)
4461> fifth_1deriv(3126) = 5.0003199590478626
4471> 4 iterations (from max of 50)
4481> fifth_2deriv(3125) = 5
4491> 4 iterations (from max of 50)
4501> fifth_2deriv(3126) = 5.0003199590478626
451[/pre]
452
453to get some (much!) diagnostic output we can add
454
455#define BOOST_MATH_INSTRUMENT
456
457[pre
4581> fifth Root finding (fifth) Example.
4591> I:\modular-boost\boost/math/tools/toms748_solve.hpp:537 a = 4 b = 8 fa = -2101 fb = 29643 count = 18
4601> I:\modular-boost\boost/math/tools/toms748_solve.hpp:340 a = 4.264742943548387 b = 8
4611> I:\modular-boost\boost/math/tools/toms748_solve.hpp:352 a = 4.264742943548387 b = 5.1409225585147951
4621> I:\modular-boost\boost/math/tools/toms748_solve.hpp:259 a = 4.264742943548387 b = 5.1409225585147951 d = 8 e = 4 fa = -1714.2037505671719 fb = 465.91652114644285 fd = 29643 fe = -2101
4631> I:\modular-boost\boost/math/tools/toms748_solve.hpp:267 q11 = -3.735257056451613 q21 = -0.045655399937094755 q31 = 0.68893005658139972 d21 = -2.9047328414222999 d31 = -0.18724955838500826
4641> I:\modular-boost\boost/math/tools/toms748_solve.hpp:275 q22 = -0.15074699539567221 q32 = 0.007740525571111408 d32 = -0.13385363287680208 q33 = 0.074868009790687237 c = 5.0362815354915851
4651> I:\modular-boost\boost/math/tools/toms748_solve.hpp:388 a = 4.264742943548387 b = 5.0362815354915851
4661> I:\modular-boost\boost/math/tools/toms748_solve.hpp:259 a = 4.264742943548387 b = 5.0362815354915851 d = 5.1409225585147951 e = 8 fa = -1714.2037505671719 fb = 115.03721886368339 fd = 465.91652114644285 fe = 29643
4671> I:\modular-boost\boost/math/tools/toms748_solve.hpp:267 q11 = -0.045655399937094755 q21 = -0.034306988726112195 q31 = 0.7230181097615842 d21 = -0.1389480117493222 d31 = -0.048520482181613811
4681> I:\modular-boost\boost/math/tools/toms748_solve.hpp:275 q22 = -0.00036345624935100459 q32 = 0.011175908093791367 d32 = -0.0030375853617102483 q33 = 0.00014618657296010219 c = 4.999083147976723
4691> I:\modular-boost\boost/math/tools/toms748_solve.hpp:408 a = 4.999083147976723 b = 5.0362815354915851
4701> I:\modular-boost\boost/math/tools/toms748_solve.hpp:433 a = 4.999083147976723 b = 5.0008904277935091
4711> I:\modular-boost\boost/math/tools/toms748_solve.hpp:434 tol = -0.00036152225583956088
4721> I:\modular-boost\boost/math/tools/toms748_solve.hpp:259 a = 4.999083147976723 b = 5.0008904277935091 d = 5.0362815354915851 e = 4.264742943548387 fa = -2.8641119933622576 fb = 2.7835781082976609 fd = 115.03721886368339 fe = -1714.2037505671719
4731> I:\modular-boost\boost/math/tools/toms748_solve.hpp:267 q11 = -0.048520482181613811 q21 = -0.00087760104664616457 q31 = 0.00091652546535745522 d21 = -0.036268708744722128 d31 = -0.00089075435142862297
4741> I:\modular-boost\boost/math/tools/toms748_solve.hpp:275 q22 = -1.9862562616034592e-005 q32 = 3.1952597740788757e-007 d32 = -1.2833778805050512e-005 q33 = 1.1763429980834706e-008 c = 5.0000000047314881
4751> I:\modular-boost\boost/math/tools/toms748_solve.hpp:388 a = 4.999083147976723 b = 5.0000000047314881
4761> I:\modular-boost\boost/math/tools/toms748_solve.hpp:259 a = 4.999083147976723 b = 5.0000000047314881 d = 5.0008904277935091 e = 5.0362815354915851 fa = -2.8641119933622576 fb = 1.4785900475544622e-005 fd = 2.7835781082976609 fe = 115.03721886368339
4771> I:\modular-boost\boost/math/tools/toms748_solve.hpp:267 q11 = -0.00087760104664616457 q21 = -4.7298032238887272e-009 q31 = 0.00091685202154135855 d21 = -0.00089042779182425238 d31 = -4.7332236912279757e-009
4781> I:\modular-boost\boost/math/tools/toms748_solve.hpp:275 q22 = -1.6486403607318402e-012 q32 = 1.7346209428817704e-012 d32 = -1.6858463963666777e-012 q33 = 9.0382569995250912e-016 c = 5
4791> I:\modular-boost\boost/math/tools/toms748_solve.hpp:592 max_iter = 10 count = 7
4801> Iterations 20
4811> 0 bits separate brackets.
4821> fifth_noderiv(3125) = 5
483]
484*/
485//] [/root_finding_example_output]