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