• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 ///////////////////////////////////////////////////////////////
2 //  Copyright 2012 John Maddock. Distributed under the Boost
3 //  Software License, Version 1.0. (See accompanying file
4 //  LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt
5 
6 #include <boost/math/constants/constants.hpp>
7 #include <boost/multiprecision/cpp_dec_float.hpp>
8 #include <boost/math/special_functions/gamma.hpp>
9 #include <boost/math/special_functions/bessel.hpp>
10 #include <iostream>
11 #include <iomanip>
12 
13 #if !defined(BOOST_NO_CXX11_HDR_ARRAY) && !defined(BOOST_NO_CXX11_LAMBDAS) && !(defined(CI_SUPPRESS_KNOWN_ISSUES) && defined(__GNUC__) && defined(_WIN32))
14 
15 #include <array>
16 
17 //[AOS1
18 
19 /*`Generic numeric programming employs templates to use the same code for different
20 floating-point types and functions. Consider the area of a circle a of radius r, given by
21 
22 [:['a = [pi] * r[super 2]]]
23 
24 The area of a circle can be computed in generic programming using Boost.Math
25 for the constant [pi] as shown below:
26 
27 */
28 
29 //=#include <boost/math/constants/constants.hpp>
30 
31 template<typename T>
area_of_a_circle(T r)32 inline T area_of_a_circle(T r)
33 {
34    using boost::math::constants::pi;
35    return pi<T>() * r * r;
36 }
37 
38 /*`
39 It is possible to use `area_of_a_circle()` with built-in floating-point types as
40 well as floating-point types from Boost.Multiprecision. In particular, consider a
41 system with 4-byte single-precision float, 8-byte double-precision double and also the
42 `cpp_dec_float_50` data type from Boost.Multiprecision with 50 decimal digits
43 of precision.
44 
45 We can compute and print the approximate area of a circle
46 with radius 123/100  for `float`, `double` and `cpp_dec_float_50` with the program below
47 (see next section for choosing 123/100  instead of 1.23).
48 
49 */
50 
51 //]
52 
53 //[AOS3
54 
55 /*`In later examples we'll look at calling both standard library and Boost.Math functions from within generic code.
56 We'll also show how to cope with template arguments which are expression-templates rather than number types.
57 
58 But first some warnings about how multiprecision types are slightly but significantly different __fundamental_types. */
59 
60 //]
61 
62 //[JEL
63 
64 /*`
65 In this example we'll show several implementations of the
66 [@http://mathworld.wolfram.com/LambdaFunction.html Jahnke and Emden Lambda function],
67 each implementation a little more sophisticated than the last.
68 
69 The Jahnke-Emden Lambda function is defined by the equation:
70 
71 [:['JahnkeEmden(v, z) = [Gamma](v+1) * J[sub v](z) / (z / 2)[super v]]]
72 
73 If we were to implement this at double precision using Boost.Math's facilities for the Gamma and Bessel
74 function calls it would look like this:
75 
76 */
77 
JEL1(double v,double z)78 double JEL1(double v, double z)
79 {
80    return boost::math::tgamma(v + 1) * boost::math::cyl_bessel_j(v, z) / std::pow(z / 2, v);
81 }
82 
83 /*`
84 Calling this function as:
85 
86    std::cout << std::scientific << std::setprecision(std::numeric_limits<double>::digits10);
87    std::cout << JEL1(2.5, 0.5) << std::endl;
88 
89 Yields the output:
90 
91 [pre 9.822663964796047e-001]
92 
93 Now let's implement the function again, but this time using the multiprecision type
94 `cpp_dec_float_50` as the argument type:
95 
96 */
97 
98 boost::multiprecision::cpp_dec_float_50
JEL2(boost::multiprecision::cpp_dec_float_50 v,boost::multiprecision::cpp_dec_float_50 z)99    JEL2(boost::multiprecision::cpp_dec_float_50 v, boost::multiprecision::cpp_dec_float_50 z)
100 {
101    return boost::math::tgamma(v + 1) * boost::math::cyl_bessel_j(v, z) / boost::multiprecision::pow(z / 2, v);
102 }
103 
104 /*`
105 The implementation is almost the same as before, but with one key difference - we can no longer call
106 `std::pow`, instead we must call the version inside the `boost::multiprecision` namespace.  In point of
107 fact, we could have omitted the namespace prefix on the call to `pow` since the right overload would
108 have been found via [@http://en.wikipedia.org/wiki/Argument-dependent_name_lookup
109 argument dependent lookup] in any case.
110 
111 Note also that the first argument to `pow` along with the argument to `tgamma` in the above code
112 are actually expression templates.  The `pow` and `tgamma` functions will handle these arguments
113 just fine.
114 
115 Here's an example of how the function may be called:
116 
117    std::cout << std::scientific << std::setprecision(std::numeric_limits<cpp_dec_float_50>::digits10);
118    std::cout << JEL2(cpp_dec_float_50(2.5), cpp_dec_float_50(0.5)) << std::endl;
119 
120 Which outputs:
121 
122 [pre 9.82266396479604757017335009796882833995903762577173e-01]
123 
124 Now that we've seen some non-template examples, lets repeat the code again, but this time as a template
125 that can be called either with a builtin type (`float`, `double` etc), or with a multiprecision type:
126 
127 */
128 
129 template <class Float>
JEL3(Float v,Float z)130 Float JEL3(Float v, Float z)
131 {
132    using std::pow;
133    return boost::math::tgamma(v + 1) * boost::math::cyl_bessel_j(v, z) / pow(z / 2, v);
134 }
135 
136 /*`
137 
138 Once again the code is almost the same as before, but the call to `pow` has changed yet again.
139 We need the call to resolve to either `std::pow` (when the argument is a builtin type), or
140 to `boost::multiprecision::pow` (when the argument is a multiprecision type).  We do that by
141 making the call unqualified so that versions of `pow` defined in the same namespace as type
142 `Float` are found via argument dependent lookup, while the `using std::pow` directive makes
143 the standard library versions visible for builtin floating point types.
144 
145 Let's call the function with both `double` and multiprecision arguments:
146 
147    std::cout << std::scientific << std::setprecision(std::numeric_limits<double>::digits10);
148    std::cout << JEL3(2.5, 0.5) << std::endl;
149    std::cout << std::scientific << std::setprecision(std::numeric_limits<cpp_dec_float_50>::digits10);
150    std::cout << JEL3(cpp_dec_float_50(2.5), cpp_dec_float_50(0.5)) << std::endl;
151 
152 Which outputs:
153 
154 [pre
155 9.822663964796047e-001
156 9.82266396479604757017335009796882833995903762577173e-01
157 ]
158 
159 Unfortunately there is a problem with this version: if we were to call it like this:
160 
161    boost::multiprecision::cpp_dec_float_50 v(2), z(0.5);
162    JEL3(v + 0.5, z);
163 
164 Then we would get a long and inscrutable error message from the compiler: the problem here is that the first
165 argument to `JEL3` is not a number type, but an expression template.  We could obviously add a typecast to
166 fix the issue:
167 
168    JEL(cpp_dec_float_50(v + 0.5), z);
169 
170 However, if we want the function JEL to be truly reusable, then a better solution might be preferred.
171 To achieve this we can borrow some code from Boost.Math which calculates the return type of mixed-argument
172 functions, here's how the new code looks now:
173 
174 */
175 
176 template <class Float1, class Float2>
177 typename boost::math::tools::promote_args<Float1, Float2>::type
JEL4(Float1 v,Float2 z)178    JEL4(Float1 v, Float2 z)
179 {
180    using std::pow;
181    return boost::math::tgamma(v + 1) * boost::math::cyl_bessel_j(v, z) / pow(z / 2, v);
182 }
183 
184 /*`
185 
186 As you can see the two arguments to the function are now separate template types, and
187 the return type is computed using the `promote_args` metafunction from Boost.Math.
188 
189 Now we can call:
190 
191    std::cout << std::scientific << std::setprecision(std::numeric_limits<cpp_dec_float_100>::digits10);
192    std::cout << JEL4(cpp_dec_float_100(2) + 0.5, cpp_dec_float_100(0.5)) << std::endl;
193 
194 And get 100 digits of output:
195 
196 [pre 9.8226639647960475701733500979688283399590376257717309069410413822165082248153638454147004236848917775e-01]
197 
198 As a bonus, we can now call the function not just with expression templates, but with other mixed types as well:
199 for example `float` and `double` or `int` and `double`, and the correct return type will be computed in each case.
200 
201 Note that while in this case we didn't have to change the body of the function, in the general case
202 any function like this which creates local variables internally would have to use `promote_args`
203 to work out what type those variables should be, for example:
204 
205    template <class Float1, class Float2>
206    typename boost::math::tools::promote_args<Float1, Float2>::type
207       JEL5(Float1 v, Float2 z)
208    {
209       using std::pow;
210       typedef typename boost::math::tools::promote_args<Float1, Float2>::type variable_type;
211       variable_type t = pow(z / 2, v);
212       return boost::math::tgamma(v + 1) * boost::math::cyl_bessel_j(v, z) / t;
213    }
214 
215 */
216 
217 //]
218 
219 //[ND1
220 
221 /*`
222 In this example we'll add even more power to generic numeric programming using not only different
223 floating-point types but also function objects as template parameters. Consider
224 some well-known central difference rules for numerically computing the first derivative
225 of a function ['f[prime](x)] with ['x [isin] [real]]:
226 
227 [equation floating_point_eg1]
228 
229 Where the difference terms ['m[sub n]] are given by:
230 
231 [equation floating_point_eg2]
232 
233 and ['dx] is the step-size of the derivative.
234 
235 The third formula in Equation 1 is a three-point central difference rule. It calculates
236 the first derivative of ['f[prime](x)] to ['O(dx[super 6])], where ['dx] is the given step-size.
237 For example, if
238 the step-size is 0.01 this derivative calculation has about 6 decimal digits of precision -
239 just about right for the 7 decimal digits of single-precision float.
240 Let's make a generic template subroutine using this three-point central difference
241 rule.  In particular:
242 */
243 
244 template<typename value_type, typename function_type>
derivative(const value_type x,const value_type dx,function_type func)245    value_type derivative(const value_type x, const value_type dx, function_type func)
246 {
247    // Compute d/dx[func(*first)] using a three-point
248    // central difference rule of O(dx^6).
249 
250    const value_type dx1 = dx;
251    const value_type dx2 = dx1 * 2;
252    const value_type dx3 = dx1 * 3;
253 
254    const value_type m1 = (func(x + dx1) - func(x - dx1)) / 2;
255    const value_type m2 = (func(x + dx2) - func(x - dx2)) / 4;
256    const value_type m3 = (func(x + dx3) - func(x - dx3)) / 6;
257 
258    const value_type fifteen_m1 = 15 * m1;
259    const value_type six_m2     =  6 * m2;
260    const value_type ten_dx1    = 10 * dx1;
261 
262    return ((fifteen_m1 - six_m2) + m3) / ten_dx1;
263 }
264 
265 /*`The `derivative()` template function can be used to compute the first derivative
266 of any function to ['O(dx[super 6])]. For example, consider the first derivative of ['sin(x)] evaluated
267 at ['x = [pi]/3]. In other words,
268 
269 [equation floating_point_eg3]
270 
271 The code below computes the derivative in Equation 3 for float, double and boost's
272 multiple-precision type cpp_dec_float_50.
273 */
274 
275 //]
276 
277 //[GI1
278 
279 /*`
280 Similar to the generic derivative example, we can calculate integrals in a similar manner:
281 */
282 
283 template<typename value_type, typename function_type>
integral(const value_type a,const value_type b,const value_type tol,function_type func)284 inline value_type integral(const value_type a,
285                            const value_type b,
286                            const value_type tol,
287                            function_type func)
288 {
289    unsigned n = 1U;
290 
291    value_type h = (b - a);
292    value_type I = (func(a) + func(b)) * (h / 2);
293 
294    for(unsigned k = 0U; k < 8U; k++)
295    {
296       h /= 2;
297 
298       value_type sum(0);
299       for(unsigned j = 1U; j <= n; j++)
300       {
301          sum += func(a + (value_type((j * 2) - 1) * h));
302       }
303 
304       const value_type I0 = I;
305       I = (I / 2) + (h * sum);
306 
307       const value_type ratio     = I0 / I;
308       const value_type delta     = ratio - 1;
309       const value_type delta_abs = ((delta < 0) ? -delta : delta);
310 
311       if((k > 1U) && (delta_abs < tol))
312       {
313          break;
314       }
315 
316       n *= 2U;
317    }
318 
319    return I;
320 }
321 
322 /*`
323 The following sample program shows how the function can be called, we begin
324 by defining a function object, which when integrated should yield the Bessel J
325 function:
326 */
327 
328 template<typename value_type>
329 class cyl_bessel_j_integral_rep
330 {
331 public:
cyl_bessel_j_integral_rep(const unsigned N,const value_type & X)332    cyl_bessel_j_integral_rep(const unsigned N,
333       const value_type& X) : n(N), x(X) { }
334 
operator ()(const value_type & t) const335    value_type operator()(const value_type& t) const
336    {
337       // pi * Jn(x) = Int_0^pi [cos(x * sin(t) - n*t) dt]
338       return cos(x * sin(t) - (n * t));
339    }
340 
341 private:
342    const unsigned n;
343    const value_type x;
344 };
345 
346 
347 //]
348 
349 //[POLY
350 
351 /*`
352 In this example we'll look at polynomial evaluation, this is not only an important
353 use case, but it's one that `number` performs particularly well at because the
354 expression templates ['completely eliminate all temporaries] from a
355 [@http://en.wikipedia.org/wiki/Horner%27s_method Horner polynomial
356 evaluation scheme].
357 
358 The following code evaluates `sin(x)` as a polynomial, accurate to at least 64 decimal places:
359 
360 */
361 
362 using boost::multiprecision::cpp_dec_float;
363 typedef boost::multiprecision::number<cpp_dec_float<64> > mp_type;
364 
mysin(const mp_type & x)365 mp_type mysin(const mp_type& x)
366 {
367   // Approximation of sin(x * pi/2) for -1 <= x <= 1, using an order 63 polynomial.
368   static const std::array<mp_type, 32U> coefs =
369   {{
370     mp_type("+1.5707963267948966192313216916397514420985846996875529104874722961539082031431044993140174126711"), //"),
371     mp_type("-0.64596409750624625365575656389794573337969351178927307696134454382929989411386887578263960484"), // ^3
372     mp_type("+0.07969262624616704512050554949047802252091164235106119545663865720995702920146198554317279"), // ^5
373     mp_type("-0.0046817541353186881006854639339534378594950280185010575749538605102665157913157426229824"), // ^7
374     mp_type("+0.00016044118478735982187266087016347332970280754062061156858775174056686380286868007443"), // ^9
375     mp_type("-3.598843235212085340458540018208389404888495232432127661083907575106196374913134E-6"), // ^11
376     mp_type("+5.692172921967926811775255303592184372902829756054598109818158853197797542565E-8"), // ^13
377     mp_type("-6.688035109811467232478226335783138689956270985704278659373558497256423498E-10"), // ^15
378     mp_type("+6.066935731106195667101445665327140070166203261129845646380005577490472E-12"), // ^17
379     mp_type("-4.377065467313742277184271313776319094862897030084226361576452003432E-14"), // ^19
380     mp_type("+2.571422892860473866153865950420487369167895373255729246889168337E-16"), // ^21
381     mp_type("-1.253899540535457665340073300390626396596970180355253776711660E-18"), // ^23
382     mp_type("+5.15645517658028233395375998562329055050964428219501277474E-21"), // ^25
383     mp_type("-1.812399312848887477410034071087545686586497030654642705E-23"), // ^27
384     mp_type("+5.50728578652238583570585513920522536675023562254864E-26"), // ^29
385     mp_type("-1.461148710664467988723468673933026649943084902958E-28"), // ^31
386     mp_type("+3.41405297003316172502972039913417222912445427E-31"), // ^33
387     mp_type("-7.07885550810745570069916712806856538290251E-34"), // ^35
388     mp_type("+1.31128947968267628970845439024155655665E-36"), // ^37
389     mp_type("-2.18318293181145698535113946654065918E-39"), // ^39
390     mp_type("+3.28462680978498856345937578502923E-42"), // ^41
391     mp_type("-4.48753699028101089490067137298E-45"), // ^43
392     mp_type("+5.59219884208696457859353716E-48"), // ^45
393     mp_type("-6.38214503973500471720565E-51"), // ^47
394     mp_type("+6.69528558381794452556E-54"), // ^49
395     mp_type("-6.47841373182350206E-57"), // ^51
396     mp_type("+5.800016389666445E-60"), // ^53
397     mp_type("-4.818507347289E-63"), // ^55
398     mp_type("+3.724683686E-66"), // ^57
399     mp_type("-2.6856479E-69"), // ^59
400     mp_type("+1.81046E-72"), // ^61
401     mp_type("-1.133E-75"), // ^63
402   }};
403 
404   const mp_type v = x * 2 / boost::math::constants::pi<mp_type>();
405   const mp_type x2 = (v * v);
406   //
407   // Polynomial evaluation follows, if mp_type allocates memory then
408   // just one such allocation occurs - to initialize the variable "sum" -
409   // and no temporaries are created at all.
410   //
411   const mp_type sum = (((((((((((((((((((((((((((((((     + coefs[31U]
412                                                      * x2 + coefs[30U])
413                                                      * x2 + coefs[29U])
414                                                      * x2 + coefs[28U])
415                                                      * x2 + coefs[27U])
416                                                      * x2 + coefs[26U])
417                                                      * x2 + coefs[25U])
418                                                      * x2 + coefs[24U])
419                                                      * x2 + coefs[23U])
420                                                      * x2 + coefs[22U])
421                                                      * x2 + coefs[21U])
422                                                      * x2 + coefs[20U])
423                                                      * x2 + coefs[19U])
424                                                      * x2 + coefs[18U])
425                                                      * x2 + coefs[17U])
426                                                      * x2 + coefs[16U])
427                                                      * x2 + coefs[15U])
428                                                      * x2 + coefs[14U])
429                                                      * x2 + coefs[13U])
430                                                      * x2 + coefs[12U])
431                                                      * x2 + coefs[11U])
432                                                      * x2 + coefs[10U])
433                                                      * x2 + coefs[9U])
434                                                      * x2 + coefs[8U])
435                                                      * x2 + coefs[7U])
436                                                      * x2 + coefs[6U])
437                                                      * x2 + coefs[5U])
438                                                      * x2 + coefs[4U])
439                                                      * x2 + coefs[3U])
440                                                      * x2 + coefs[2U])
441                                                      * x2 + coefs[1U])
442                                                      * x2 + coefs[0U])
443                                                      * v;
444 
445   return sum;
446 }
447 
448 /*`
449 Calling the function like so:
450 
451    mp_type pid4 = boost::math::constants::pi<mp_type>() / 4;
452    std::cout << std::setprecision(std::numeric_limits< ::mp_type>::digits10) << std::scientific;
453    std::cout << mysin(pid4) << std::endl;
454 
455 Yields the expected output:
456 
457 [pre 7.0710678118654752440084436210484903928483593768847403658833986900e-01]
458 
459 */
460 
461 //]
462 
463 
main()464 int main()
465 {
466    using namespace boost::multiprecision;
467    std::cout << std::scientific << std::setprecision(std::numeric_limits<double>::digits10);
468    std::cout << JEL1(2.5, 0.5) << std::endl;
469    std::cout << std::scientific << std::setprecision(std::numeric_limits<cpp_dec_float_50>::digits10);
470    std::cout << JEL2(cpp_dec_float_50(2.5), cpp_dec_float_50(0.5)) << std::endl;
471    std::cout << std::scientific << std::setprecision(std::numeric_limits<double>::digits10);
472    std::cout << JEL3(2.5, 0.5) << std::endl;
473    std::cout << std::scientific << std::setprecision(std::numeric_limits<cpp_dec_float_50>::digits10);
474    std::cout << JEL3(cpp_dec_float_50(2.5), cpp_dec_float_50(0.5)) << std::endl;
475    std::cout << std::scientific << std::setprecision(std::numeric_limits<cpp_dec_float_100>::digits10);
476    std::cout << JEL4(cpp_dec_float_100(2) + 0.5, cpp_dec_float_100(0.5)) << std::endl;
477 
478    //[AOS2
479 
480 /*=#include <iostream>
481 #include <iomanip>
482 #include <boost/multiprecision/cpp_dec_float.hpp>
483 
484 using boost::multiprecision::cpp_dec_float_50;
485 
486 int main(int, char**)
487 {*/
488    const float r_f(float(123) / 100);
489    const float a_f = area_of_a_circle(r_f);
490 
491    const double r_d(double(123) / 100);
492    const double a_d = area_of_a_circle(r_d);
493 
494    const cpp_dec_float_50 r_mp(cpp_dec_float_50(123) / 100);
495    const cpp_dec_float_50 a_mp = area_of_a_circle(r_mp);
496 
497    // 4.75292
498    std::cout
499       << std::setprecision(std::numeric_limits<float>::digits10)
500       << a_f
501       << std::endl;
502 
503    // 4.752915525616
504    std::cout
505       << std::setprecision(std::numeric_limits<double>::digits10)
506       << a_d
507       << std::endl;
508 
509    // 4.7529155256159981904701331745635599135018975843146
510    std::cout
511       << std::setprecision(std::numeric_limits<cpp_dec_float_50>::digits10)
512       << a_mp
513       << std::endl;
514 /*=}*/
515 
516    //]
517 
518    //[ND2
519 /*=
520 #include <iostream>
521 #include <iomanip>
522 #include <boost/multiprecision/cpp_dec_float.hpp>
523 #include <boost/math/constants/constants.hpp>
524 
525 
526 int main(int, char**)
527 {*/
528    using boost::math::constants::pi;
529    using boost::multiprecision::cpp_dec_float_50;
530    //
531    // We'll pass a function pointer for the function object passed to derivative,
532    // the typecast is needed to select the correct overload of std::sin:
533    //
534    const float d_f = derivative(
535       pi<float>() / 3,
536       0.01F,
537       static_cast<float(*)(float)>(std::sin)
538    );
539 
540    const double d_d = derivative(
541       pi<double>() / 3,
542       0.001,
543       static_cast<double(*)(double)>(std::sin)
544       );
545    //
546    // In the cpp_dec_float_50 case, the sin function is multiply overloaded
547    // to handle expression templates etc.  As a result it's hard to take its
548    // address without knowing about its implementation details.  We'll use a
549    // C++11 lambda expression to capture the call.
550    // We also need a typecast on the first argument so we don't accidentally pass
551    // an expression template to a template function:
552    //
553    const cpp_dec_float_50 d_mp = derivative(
554       cpp_dec_float_50(pi<cpp_dec_float_50>() / 3),
555       cpp_dec_float_50(1.0E-9),
556       [](const cpp_dec_float_50& x) -> cpp_dec_float_50
557       {
558          return sin(x);
559       }
560       );
561 
562    // 5.000029e-001
563    std::cout
564       << std::setprecision(std::numeric_limits<float>::digits10)
565       << d_f
566       << std::endl;
567 
568    // 4.999999999998876e-001
569    std::cout
570       << std::setprecision(std::numeric_limits<double>::digits10)
571       << d_d
572       << std::endl;
573 
574    // 4.99999999999999999999999999999999999999999999999999e-01
575    std::cout
576       << std::setprecision(std::numeric_limits<cpp_dec_float_50>::digits10)
577       << d_mp
578       << std::endl;
579 //=}
580 
581    /*`
582    The expected value of the derivative is 0.5. This central difference rule in this
583    example is ill-conditioned, meaning it suffers from slight loss of precision. With that
584    in mind, the results agree with the expected value of 0.5.*/
585 
586    //]
587 
588    //[ND3
589 
590    /*`
591    We can take this a step further and use our derivative function to compute
592    a partial derivative.  For example if we take the incomplete gamma function
593    ['P(a, z)], and take the derivative with respect to /z/ at /(2,2)/ then we
594    can calculate the result as shown below, for good measure we'll compare with
595    the "correct" result obtained from a call to ['gamma_p_derivative], the results
596    agree to approximately 44 digits:
597    */
598 
599    cpp_dec_float_50 gd = derivative(
600       cpp_dec_float_50(2),
601       cpp_dec_float_50(1.0E-9),
602       [](const cpp_dec_float_50& x) ->cpp_dec_float_50
603       {
604          return boost::math::gamma_p(2, x);
605       }
606    );
607    // 2.70670566473225383787998989944968806815263091819151e-01
608    std::cout
609       << std::setprecision(std::numeric_limits<cpp_dec_float_50>::digits10)
610       << gd
611       << std::endl;
612    // 2.70670566473225383787998989944968806815253190143120e-01
613    std::cout << boost::math::gamma_p_derivative(cpp_dec_float_50(2), cpp_dec_float_50(2)) << std::endl;
614    //]
615 
616    //[GI2
617 
618    /* The function can now be called as follows: */
619 /*=int main(int, char**)
620 {*/
621    using boost::math::constants::pi;
622    typedef boost::multiprecision::cpp_dec_float_50 mp_type;
623 
624    const float j2_f =
625       integral(0.0F,
626       pi<float>(),
627       0.01F,
628       cyl_bessel_j_integral_rep<float>(2U, 1.23F)) / pi<float>();
629 
630    const double j2_d =
631       integral(0.0,
632       pi<double>(),
633       0.0001,
634       cyl_bessel_j_integral_rep<double>(2U, 1.23)) / pi<double>();
635 
636    const mp_type j2_mp =
637       integral(mp_type(0),
638       pi<mp_type>(),
639       mp_type(1.0E-20),
640       cyl_bessel_j_integral_rep<mp_type>(2U, mp_type(123) / 100)) / pi<mp_type>();
641 
642    // 0.166369
643    std::cout
644       << std::setprecision(std::numeric_limits<float>::digits10)
645       << j2_f
646       << std::endl;
647 
648    // 0.166369383786814
649    std::cout
650       << std::setprecision(std::numeric_limits<double>::digits10)
651       << j2_d
652       << std::endl;
653 
654    // 0.16636938378681407351267852431513159437103348245333
655    std::cout
656       << std::setprecision(std::numeric_limits<mp_type>::digits10)
657       << j2_mp
658       << std::endl;
659 
660    //
661    // Print true value for comparison:
662    // 0.166369383786814073512678524315131594371033482453329
663    std::cout << boost::math::cyl_bessel_j(2, mp_type(123) / 100) << std::endl;
664 //=}
665 
666    //]
667 
668    std::cout << std::setprecision(std::numeric_limits< ::mp_type>::digits10) << std::scientific;
669    std::cout << mysin(boost::math::constants::pi< ::mp_type>() / 4) << std::endl;
670    std::cout << boost::multiprecision::sin(boost::math::constants::pi< ::mp_type>() / 4) << std::endl;
671 
672    return 0;
673 }
674 
675 /*
676 
677 Program output:
678 
679 9.822663964796047e-001
680 9.82266396479604757017335009796882833995903762577173e-01
681 9.822663964796047e-001
682 9.82266396479604757017335009796882833995903762577173e-01
683 9.8226639647960475701733500979688283399590376257717309069410413822165082248153638454147004236848917775e-01
684 4.752916e+000
685 4.752915525615998e+000
686 4.75291552561599819047013317456355991350189758431460e+00
687 5.000029e-001
688 4.999999999998876e-001
689 4.99999999999999999999999999999999999999999999999999e-01
690 2.70670566473225383787998989944968806815263091819151e-01
691 2.70670566473225383787998989944968806815253190143120e-01
692 7.0710678118654752440084436210484903928483593768847403658833986900e-01
693 7.0710678118654752440084436210484903928483593768847403658833986900e-01
694 */
695 
696 #else
697 
main()698 int main() { return 0; }
699 
700 #endif
701