root_finding_n_example.cpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. // Copyright Paul A. Bristow 2014, 2015.
  2. // Use, modification and distribution are subject to the
  3. // Boost Software License, Version 1.0.
  4. // (See accompanying file LICENSE_1_0.txt
  5. // or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. // Note that this file contains Quickbook mark-up as well as code
  7. // and comments, don't change any of the special comment mark-ups!
  8. // Example of finding nth root using 1st and 2nd derivatives of x^n.
  9. #include <boost/math/tools/roots.hpp>
  10. //using boost::math::policies::policy;
  11. //using boost::math::tools::newton_raphson_iterate;
  12. //using boost::math::tools::halley_iterate;
  13. //using boost::math::tools::eps_tolerance; // Binary functor for specified number of bits.
  14. //using boost::math::tools::bracket_and_solve_root;
  15. //using boost::math::tools::toms748_solve;
  16. #include <boost/math/special_functions/next.hpp>
  17. #include <boost/multiprecision/cpp_dec_float.hpp>
  18. #include <boost/math/special_functions/pow.hpp>
  19. #include <boost/math/constants/constants.hpp>
  20. #include <boost/multiprecision/cpp_dec_float.hpp> // For cpp_dec_float_50.
  21. #include <boost/multiprecision/cpp_bin_float.hpp> // using boost::multiprecision::cpp_bin_float_50;
  22. #ifndef _MSC_VER // float128 is not yet supported by Microsoft compiler at 2013.
  23. # include <boost/multiprecision/float128.hpp>
  24. #endif
  25. #include <iostream>
  26. // using std::cout; using std::endl;
  27. #include <iomanip>
  28. // using std::setw; using std::setprecision;
  29. #include <limits>
  30. using std::numeric_limits;
  31. #include <tuple>
  32. #include <utility> // pair, make_pair
  33. //[root_finding_nth_functor_2deriv
  34. template <int N, class T = double>
  35. struct nth_functor_2deriv
  36. { // Functor returning both 1st and 2nd derivatives.
  37. BOOST_STATIC_ASSERT_MSG(boost::is_integral<T>::value == false, "Only floating-point type types can be used!");
  38. BOOST_STATIC_ASSERT_MSG((N > 0) == true, "root N must be > 0!");
  39. nth_functor_2deriv(T const& to_find_root_of) : a(to_find_root_of)
  40. { /* Constructor stores value a to find root of, for example: */ }
  41. // using boost::math::tuple; // to return three values.
  42. std::tuple<T, T, T> operator()(T const& x)
  43. {
  44. // Return f(x), f'(x) and f''(x).
  45. using boost::math::pow;
  46. T fx = pow<N>(x) - a; // Difference (estimate x^n - a).
  47. T dx = N * pow<N - 1>(x); // 1st derivative f'(x).
  48. T d2x = N * (N - 1) * pow<N - 2 >(x); // 2nd derivative f''(x).
  49. return std::make_tuple(fx, dx, d2x); // 'return' fx, dx and d2x.
  50. }
  51. private:
  52. T a; // to be 'nth_rooted'.
  53. };
  54. //] [/root_finding_nth_functor_2deriv]
  55. /*
  56. To show the progress, one might use this before the return statement above?
  57. #ifdef BOOST_MATH_ROOT_DIAGNOSTIC
  58. std::cout << " x = " << x << ", fx = " << fx << ", dx = " << dx << ", dx2 = " << d2x << std::endl;
  59. #endif
  60. */
  61. // If T is a floating-point type, might be quicker to compute the guess using a built-in type,
  62. // probably quickest using double, but perhaps with float or long double, T.
  63. // If T is a type for which frexp and ldexp are not defined,
  64. // then it is necessary to compute the guess using a built-in type,
  65. // probably quickest (but limited range) using double,
  66. // but perhaps with float or long double, or a multiprecision T for the full range of T.
  67. // typedef double guess_type; is used to specify the this.
  68. //[root_finding_nth_function_2deriv
  69. template <int N, class T = double>
  70. T nth_2deriv(T x)
  71. { // return nth root of x using 1st and 2nd derivatives and Halley.
  72. using namespace std; // Help ADL of std functions.
  73. using namespace boost::math::tools; // For halley_iterate.
  74. BOOST_STATIC_ASSERT_MSG(boost::is_integral<T>::value == false, "Only floating-point type types can be used!");
  75. BOOST_STATIC_ASSERT_MSG((N > 0) == true, "root N must be > 0!");
  76. BOOST_STATIC_ASSERT_MSG((N > 1000) == false, "root N is too big!");
  77. typedef double guess_type; // double may restrict (exponent) range for a multiprecision T?
  78. int exponent;
  79. frexp(static_cast<guess_type>(x), &exponent); // Get exponent of z (ignore mantissa).
  80. T guess = ldexp(static_cast<guess_type>(1.), exponent / N); // Rough guess is to divide the exponent by n.
  81. T min = ldexp(static_cast<guess_type>(1.) / 2, exponent / N); // Minimum possible value is half our guess.
  82. T max = ldexp(static_cast<guess_type>(2.), exponent / N); // Maximum possible value is twice our guess.
  83. int digits = std::numeric_limits<T>::digits * 0.4; // Accuracy triples with each step, so stop when
  84. // slightly more than one third of the digits are correct.
  85. const boost::uintmax_t maxit = 20;
  86. boost::uintmax_t it = maxit;
  87. T result = halley_iterate(nth_functor_2deriv<N, T>(x), guess, min, max, digits, it);
  88. return result;
  89. }
  90. //] [/root_finding_nth_function_2deriv]
  91. template <int N, typename T = double>
  92. T show_nth_root(T value)
  93. { // Demonstrate by printing the nth root using all possibly significant digits.
  94. //std::cout.precision(std::numeric_limits<T>::max_digits10);
  95. // or use cout.precision(max_digits10 = 2 + std::numeric_limits<double>::digits * 3010/10000);
  96. // Or guaranteed significant digits:
  97. std::cout.precision(std::numeric_limits<T>::digits10);
  98. T r = nth_2deriv<N>(value);
  99. std::cout << "Type " << typeid(T).name() << " value = " << value << ", " << N << "th root = " << r << std::endl;
  100. return r;
  101. } // print_nth_root
  102. int main()
  103. {
  104. std::cout << "nth Root finding Example." << std::endl;
  105. using boost::multiprecision::cpp_dec_float_50; // decimal.
  106. using boost::multiprecision::cpp_bin_float_50; // binary.
  107. #ifndef _MSC_VER // Not supported by Microsoft compiler.
  108. using boost::multiprecision::float128; // Requires libquadmath
  109. #endif
  110. try
  111. { // Always use try'n'catch blocks with Boost.Math to get any error messages.
  112. //[root_finding_n_example_1
  113. double r1 = nth_2deriv<5, double>(2); // Integral value converted to double.
  114. // double r2 = nth_2deriv<5>(2); // Only floating-point type types can be used!
  115. //] [/root_finding_n_example_1
  116. //show_nth_root<5, float>(2); // Integral value converted to float.
  117. //show_nth_root<5, float>(2.F); // 'initializing' : conversion from 'double' to 'float', possible loss of data
  118. //[root_finding_n_example_2
  119. show_nth_root<5, double>(2.);
  120. show_nth_root<5, long double>(2.);
  121. #ifndef _MSC_VER // float128 is not supported by Microsoft compiler 2013.
  122. show_nth_root<5, float128>(2);
  123. #endif
  124. show_nth_root<5, cpp_dec_float_50>(2); // dec
  125. show_nth_root<5, cpp_bin_float_50>(2); // bin
  126. //] [/root_finding_n_example_2
  127. // show_nth_root<1000000>(2.); // Type double value = 2, 555th root = 1.00124969405651
  128. // Type double value = 2, 1000th root = 1.00069338746258
  129. // Type double value = 2, 1000000th root = 1.00000069314783
  130. }
  131. catch (const std::exception& e)
  132. { // Always useful to include try & catch blocks because default policies
  133. // are to throw exceptions on arguments that cause errors like underflow, overflow.
  134. // Lacking try & catch blocks, the program will abort without a message below,
  135. // which may give some helpful clues as to the cause of the exception.
  136. std::cout <<
  137. "\n""Message from thrown exception was:\n " << e.what() << std::endl;
  138. }
  139. return 0;
  140. } // int main()
  141. /*
  142. //[root_finding_example_output_1
  143. Using MSVC 2013
  144. nth Root finding Example.
  145. Type double value = 2, 5th root = 1.14869835499704
  146. Type long double value = 2, 5th root = 1.14869835499704
  147. Type class boost::multiprecision::number<class boost::multiprecision::backends::cpp_dec_float<50,int,void>,1> value = 2,
  148. 5th root = 1.1486983549970350067986269467779275894438508890978
  149. Type class boost::multiprecision::number<class boost::multiprecision::backends::cpp_bin_float<50,10,void,int,0,0>,0> value = 2,
  150. 5th root = 1.1486983549970350067986269467779275894438508890978
  151. //] [/root_finding_example_output_1]
  152. //[root_finding_example_output_2
  153. Using GCC 4.91 (includes float_128 type)
  154. nth Root finding Example.
  155. Type d value = 2, 5th root = 1.14869835499704
  156. Type e value = 2, 5th root = 1.14869835499703501
  157. Type N5boost14multiprecision6numberINS0_8backends16float128_backendELNS0_26expression_template_optionE0EEE value = 2, 5th root = 1.148698354997035006798626946777928
  158. Type N5boost14multiprecision6numberINS0_8backends13cpp_dec_floatILj50EivEELNS0_26expression_template_optionE1EEE value = 2, 5th root = 1.1486983549970350067986269467779275894438508890978
  159. Type N5boost14multiprecision6numberINS0_8backends13cpp_bin_floatILj50ELNS2_15digit_base_typeE10EviLi0ELi0EEELNS0_26expression_template_optionE0EEE value = 2, 5th root = 1.1486983549970350067986269467779275894438508890978
  160. RUN SUCCESSFUL (total time: 63ms)
  161. //] [/root_finding_example_output_2]
  162. */
  163. /*
  164. Throw out of range using GCC release mode :-(
  165. */