root_finding_multiprecision_example.cpp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. // Copyright Paul A. Bristow 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 root finding using Boost.Multiprecision.
  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> // For float_distance.
  17. #include <boost/math/special_functions/pow.hpp>
  18. #include <boost/math/constants/constants.hpp>
  19. //[root_finding_multiprecision_include_1
  20. #include <boost/multiprecision/cpp_bin_float.hpp> // For cpp_bin_float_50.
  21. #include <boost/multiprecision/cpp_dec_float.hpp> // For cpp_dec_float_50.
  22. #ifndef _MSC_VER // float128 is not yet supported by Microsoft compiler at 2013.
  23. # include <boost/multiprecision/float128.hpp> // Requires libquadmath.
  24. #endif
  25. //] [/root_finding_multiprecision_include_1]
  26. #include <iostream>
  27. // using std::cout; using std::endl;
  28. #include <iomanip>
  29. // using std::setw; using std::setprecision;
  30. #include <limits>
  31. // using std::numeric_limits;
  32. #include <tuple>
  33. #include <utility> // pair, make_pair
  34. // #define BUILTIN_POW_GUESS // define to use std::pow function to obtain a guess.
  35. template <class T>
  36. T cbrt_2deriv(T x)
  37. { // return cube root of x using 1st and 2nd derivatives and Halley.
  38. using namespace std; // Help ADL of std functions.
  39. using namespace boost::math::tools; // For halley_iterate.
  40. // If T is not a binary floating-point type, for example, cpp_dec_float_50
  41. // then frexp may not be defined,
  42. // so it may be necessary to compute the guess using a built-in type,
  43. // probably quickest using double, but perhaps with float or long double.
  44. // Note that the range of exponent may be restricted by a built-in-type for guess.
  45. typedef long double guess_type;
  46. #ifdef BUILTIN_POW_GUESS
  47. guess_type pow_guess = std::pow(static_cast<guess_type>(x), static_cast<guess_type>(1) / 3);
  48. T guess = pow_guess;
  49. T min = pow_guess /2;
  50. T max = pow_guess * 2;
  51. #else
  52. int exponent;
  53. frexp(static_cast<guess_type>(x), &exponent); // Get exponent of z (ignore mantissa).
  54. T guess = ldexp(static_cast<guess_type>(1.), exponent / 3); // Rough guess is to divide the exponent by three.
  55. T min = ldexp(static_cast<guess_type>(1.) / 2, exponent / 3); // Minimum possible value is half our guess.
  56. T max = ldexp(static_cast<guess_type>(2.), exponent / 3); // Maximum possible value is twice our guess.
  57. #endif
  58. int digits = std::numeric_limits<T>::digits / 2; // Half maximum possible binary digits accuracy for type T.
  59. const boost::uintmax_t maxit = 20;
  60. boost::uintmax_t it = maxit;
  61. T result = halley_iterate(cbrt_functor_2deriv<T>(x), guess, min, max, digits, it);
  62. // Can show how many iterations (updated by halley_iterate).
  63. // std::cout << "Iterations " << it << " (from max of "<< maxit << ")." << std::endl;
  64. return result;
  65. } // cbrt_2deriv(x)
  66. template <class T>
  67. struct cbrt_functor_2deriv
  68. { // Functor returning both 1st and 2nd derivatives.
  69. cbrt_functor_2deriv(T const& to_find_root_of) : a(to_find_root_of)
  70. { // Constructor stores value to find root of, for example:
  71. }
  72. // using boost::math::tuple; // to return three values.
  73. std::tuple<T, T, T> operator()(T const& x)
  74. {
  75. // Return both f(x) and f'(x) and f''(x).
  76. T fx = x*x*x - a; // Difference (estimate x^3 - value).
  77. // std::cout << "x = " << x << "\nfx = " << fx << std::endl;
  78. T dx = 3 * x*x; // 1st derivative = 3x^2.
  79. T d2x = 6 * x; // 2nd derivative = 6x.
  80. return std::make_tuple(fx, dx, d2x); // 'return' fx, dx and d2x.
  81. }
  82. private:
  83. T a; // to be 'cube_rooted'.
  84. }; // struct cbrt_functor_2deriv
  85. template <int n, class T>
  86. struct nth_functor_2deriv
  87. { // Functor returning both 1st and 2nd derivatives.
  88. nth_functor_2deriv(T const& to_find_root_of) : value(to_find_root_of)
  89. { /* Constructor stores value to find root of, for example: */ }
  90. // using std::tuple; // to return three values.
  91. std::tuple<T, T, T> operator()(T const& x)
  92. {
  93. // Return both f(x) and f'(x) and f''(x).
  94. using boost::math::pow;
  95. T fx = pow<n>(x) - value; // Difference (estimate x^3 - value).
  96. T dx = n * pow<n - 1>(x); // 1st derivative = 5x^4.
  97. T d2x = n * (n - 1) * pow<n - 2 >(x); // 2nd derivative = 20 x^3
  98. return std::make_tuple(fx, dx, d2x); // 'return' fx, dx and d2x.
  99. }
  100. private:
  101. T value; // to be 'nth_rooted'.
  102. }; // struct nth_functor_2deriv
  103. template <int n, class T>
  104. T nth_2deriv(T x)
  105. {
  106. // return nth root of x using 1st and 2nd derivatives and Halley.
  107. using namespace std; // Help ADL of std functions.
  108. using namespace boost::math; // For halley_iterate.
  109. int exponent;
  110. frexp(x, &exponent); // Get exponent of z (ignore mantissa).
  111. T guess = ldexp(static_cast<T>(1.), exponent / n); // Rough guess is to divide the exponent by three.
  112. T min = ldexp(static_cast<T>(0.5), exponent / n); // Minimum possible value is half our guess.
  113. T max = ldexp(static_cast<T>(2.), exponent / n); // Maximum possible value is twice our guess.
  114. int digits = std::numeric_limits<T>::digits / 2; // Half maximum possible binary digits accuracy for type T.
  115. const boost::uintmax_t maxit = 50;
  116. boost::uintmax_t it = maxit;
  117. T result = halley_iterate(nth_functor_2deriv<n, T>(x), guess, min, max, digits, it);
  118. // Can show how many iterations (updated by halley_iterate).
  119. std::cout << it << " iterations (from max of " << maxit << ")" << std::endl;
  120. return result;
  121. } // nth_2deriv(x)
  122. //[root_finding_multiprecision_show_1
  123. template <typename T>
  124. T show_cube_root(T value)
  125. { // Demonstrate by printing the root using all definitely significant digits.
  126. std::cout.precision(std::numeric_limits<T>::digits10);
  127. T r = cbrt_2deriv(value);
  128. std::cout << "value = " << value << ", cube root =" << r << std::endl;
  129. return r;
  130. }
  131. //] [/root_finding_multiprecision_show_1]
  132. int main()
  133. {
  134. std::cout << "Multiprecision Root finding Example." << std::endl;
  135. // Show all possibly significant decimal digits.
  136. std::cout.precision(std::numeric_limits<double>::digits10);
  137. // or use cout.precision(max_digits10 = 2 + std::numeric_limits<double>::digits * 3010/10000);
  138. //[root_finding_multiprecision_example_1
  139. using boost::multiprecision::cpp_dec_float_50; // decimal.
  140. using boost::multiprecision::cpp_bin_float_50; // binary.
  141. #ifndef _MSC_VER // Not supported by Microsoft compiler.
  142. using boost::multiprecision::float128;
  143. #endif
  144. //] [/root_finding_multiprecision_example_1
  145. try
  146. { // Always use try'n'catch blocks with Boost.Math to get any error messages.
  147. // Increase the precision to 50 decimal digits using Boost.Multiprecision
  148. //[root_finding_multiprecision_example_2
  149. std::cout.precision(std::numeric_limits<cpp_dec_float_50>::digits10);
  150. cpp_dec_float_50 two = 2; //
  151. cpp_dec_float_50 r = cbrt_2deriv(two);
  152. std::cout << "cbrt(" << two << ") = " << r << std::endl;
  153. r = cbrt_2deriv(2.); // Passing a double, so ADL will compute a double precision result.
  154. std::cout << "cbrt(" << two << ") = " << r << std::endl;
  155. // cbrt(2) = 1.2599210498948731906665443602832965552806854248047 'wrong' from digits 17 onwards!
  156. r = cbrt_2deriv(static_cast<cpp_dec_float_50>(2.)); // Passing a cpp_dec_float_50,
  157. // so will compute a cpp_dec_float_50 precision result.
  158. std::cout << "cbrt(" << two << ") = " << r << std::endl;
  159. r = cbrt_2deriv<cpp_dec_float_50>(2.); // Explictly a cpp_dec_float_50, so will compute a cpp_dec_float_50 precision result.
  160. std::cout << "cbrt(" << two << ") = " << r << std::endl;
  161. // cpp_dec_float_50 1.2599210498948731647672106072782283505702514647015
  162. //] [/root_finding_multiprecision_example_2
  163. // N[2^(1/3), 50] 1.2599210498948731647672106072782283505702514647015
  164. //show_cube_root(2); // Integer parameter - Errors!
  165. //show_cube_root(2.F); // Float parameter - Warnings!
  166. //[root_finding_multiprecision_example_3
  167. show_cube_root(2.);
  168. show_cube_root(2.L);
  169. show_cube_root(two);
  170. //] [/root_finding_multiprecision_example_3
  171. }
  172. catch (const std::exception& e)
  173. { // Always useful to include try&catch blocks because default policies
  174. // are to throw exceptions on arguments that cause errors like underflow & overflow.
  175. // Lacking try&catch blocks, the program will abort without a message below,
  176. // which may give some helpful clues as to the cause of the exception.
  177. std::cout <<
  178. "\n""Message from thrown exception was:\n " << e.what() << std::endl;
  179. }
  180. return 0;
  181. } // int main()
  182. /*
  183. Description: Autorun "J:\Cpp\MathToolkit\test\Math_test\Release\root_finding_multiprecision.exe"
  184. Multiprecision Root finding Example.
  185. cbrt(2) = 1.2599210498948731647672106072782283505702514647015
  186. cbrt(2) = 1.2599210498948731906665443602832965552806854248047
  187. cbrt(2) = 1.2599210498948731647672106072782283505702514647015
  188. cbrt(2) = 1.2599210498948731647672106072782283505702514647015
  189. value = 2, cube root =1.25992104989487
  190. value = 2, cube root =1.25992104989487
  191. value = 2, cube root =1.2599210498948731647672106072782283505702514647015
  192. */