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