1 // Copyright Nick Thompson, 2017
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)
7 #define BOOST_TEST_MODULE exp_sinh_quadrature_test
9 #include <boost/math/concepts/real_concept.hpp>
10 #include <boost/test/included/unit_test.hpp>
11 #include <boost/test/floating_point_comparison.hpp>
12 #include <boost/math/quadrature/exp_sinh.hpp>
13 #include <boost/math/special_functions/sinc.hpp>
14 #include <boost/math/special_functions/bessel.hpp>
15 #include <boost/multiprecision/cpp_bin_float.hpp>
16 #include <boost/multiprecision/cpp_dec_float.hpp>
17 #include <boost/math/special_functions/next.hpp>
18 #include <boost/math/special_functions/gamma.hpp>
19 #include <boost/math/special_functions/sinc.hpp>
20 #include <boost/type_traits/is_class.hpp>
32 using boost::multiprecision::cpp_bin_float_50
;
33 using boost::multiprecision::cpp_bin_float_100
;
34 using boost::multiprecision::cpp_bin_float_quad
;
35 using boost::math::constants::pi
;
36 using boost::math::constants::half_pi
;
37 using boost::math::constants::two_div_pi
;
38 using boost::math::constants::half
;
39 using boost::math::constants::third
;
40 using boost::math::constants::half
;
41 using boost::math::constants::third
;
42 using boost::math::constants::catalan
;
43 using boost::math::constants::ln_two
;
44 using boost::math::constants::root_two
;
45 using boost::math::constants::root_two_pi
;
46 using boost::math::constants::root_pi
;
47 using boost::math::quadrature::exp_sinh
;
49 #if !defined(TEST1) && !defined(TEST2) && !defined(TEST3) && !defined(TEST4) && !defined(TEST5) && !defined(TEST6) && !defined(TEST7)
60 #pragma warning (disable:4127)
64 // Coefficient generation code:
67 void print_levels(const T
& v
, const char* suffix
)
70 for (unsigned i
= 0; i
< v
.size(); ++i
)
73 for (unsigned j
= 0; j
< v
[i
].size(); ++j
)
75 std::cout
<< v
[i
][j
] << suffix
<< ", ";
83 void print_levels(const std::pair
<T
, T
>& p
, const char* suffix
= "")
85 std::cout
<< " static const std::vector<std::vector<Real> > abscissa = ";
86 print_levels(p
.first
, suffix
);
87 std::cout
<< " static const std::vector<std::vector<Real> > weights = ";
88 print_levels(p
.second
, suffix
);
91 template <class Real
, class TargetType
>
92 std::pair
<std::vector
<std::vector
<Real
>>, std::vector
<std::vector
<Real
>> > generate_constants(unsigned max_rows
)
94 using boost::math::constants::half_pi
;
95 using boost::math::constants::two_div_pi
;
96 using boost::math::constants::pi
;
97 auto g
= [](Real t
) { return exp(half_pi
<Real
>()*sinh(t
)); };
98 auto w
= [](Real t
) { return cosh(t
)*half_pi
<Real
>()*exp(half_pi
<Real
>()*sinh(t
)); };
100 std::vector
<std::vector
<Real
>> abscissa
, weights
;
102 std::vector
<Real
> temp
;
104 Real tmp
= (Real(boost::math::tools::log_min_value
<TargetType
>()) + log(Real(boost::math::tools::epsilon
<TargetType
>())))*0.5f
;
105 Real t_min
= asinh(two_div_pi
<Real
>()*tmp
);
106 // truncate t_min to an exact binary value:
107 t_min
= floor(t_min
* 128) / 128;
109 std::cout
<< "m_t_min = " << t_min
<< ";\n";
111 // t_max is chosen to make g'(t_max) ~ sqrt(max) (g' grows faster than g).
112 // This will allow some flexibility on the users part; they can at least square a number function without overflow.
113 // But there is no unique choice; the further out we can evaluate the function, the better we can do on slowly decaying integrands.
114 const Real t_max
= log(2 * two_div_pi
<Real
>()*log(2 * two_div_pi
<Real
>()*sqrt(Real(boost::math::tools::max_value
<TargetType
>()))));
117 for (Real t
= t_min
; t
< t_max
; t
+= h
)
119 temp
.push_back(g(t
));
121 abscissa
.push_back(temp
);
124 for (Real t
= t_min
; t
< t_max
; t
+= h
)
126 temp
.push_back(w(t
* h
));
128 weights
.push_back(temp
);
131 for (unsigned row
= 1; row
< max_rows
; ++row
)
134 for (Real t
= t_min
+ h
; t
< t_max
; t
+= 2 * h
)
135 temp
.push_back(g(t
));
136 abscissa
.push_back(temp
);
140 for (unsigned row
= 1; row
< max_rows
; ++row
)
143 for (Real t
= t_min
+ h
; t
< t_max
; t
+= 2 * h
)
144 temp
.push_back(w(t
));
145 weights
.push_back(temp
);
149 return std::make_pair(abscissa
, weights
);
153 template <class Real
>
154 const exp_sinh
<Real
>& get_integrator()
156 static const exp_sinh
<Real
> integrator(14);
160 template <class Real
>
161 Real
get_convergence_tolerance()
163 return boost::math::tools::root_epsilon
<Real
>();
167 void test_right_limit_infinite()
169 std::cout
<< "Testing right limit infinite for tanh_sinh in 'A Comparison of Three High Precision Quadrature Schemes' on type " << boost::typeindex::type_id
<Real
>().pretty_name() << "\n";
170 Real tol
= 10 * boost::math::tools::epsilon
<Real
>();
175 auto integrator
= get_integrator
<Real
>();
178 const auto f2
= [](const Real
& t
) { return exp(-t
)/sqrt(t
); };
179 Q
= integrator
.integrate(f2
, get_convergence_tolerance
<Real
>(), &error
, &L1
);
180 Q_expected
= root_pi
<Real
>();
182 // Multiprecision type have higher error rates, probably evaluation of f() is less accurate:
183 if (std::numeric_limits
<Real
>::digits10
> std::numeric_limits
<long double>::digits10
)
185 else if (std::numeric_limits
<Real
>::digits10
> std::numeric_limits
<double>::digits10
)
187 BOOST_CHECK_CLOSE_FRACTION(Q
, Q_expected
, tol
* tol_mult
);
188 // The integrand is strictly positive, so it coincides with the value of the integral:
189 BOOST_CHECK_CLOSE_FRACTION(L1
, Q_expected
, tol
* tol_mult
);
191 auto f3
= [](Real t
)->Real
{ Real z
= exp(-t
); if (z
== 0) { return z
; } return z
*cos(t
); };
192 Q
= integrator
.integrate(f3
, get_convergence_tolerance
<Real
>(), &error
, &L1
);
193 Q_expected
= half
<Real
>();
194 BOOST_CHECK_CLOSE_FRACTION(Q
, Q_expected
, tol
);
195 Q
= integrator
.integrate(f3
, 10, std::numeric_limits
<Real
>::has_infinity
? std::numeric_limits
<Real
>::infinity() : boost::math::tools::max_value
<Real
>(), get_convergence_tolerance
<Real
>(), &error
, &L1
);
196 Q_expected
= boost::lexical_cast
<Real
>("-6.6976341310426674140007086979326069121526743314567805278252392932e-6");
197 BOOST_CHECK_CLOSE_FRACTION(Q
, Q_expected
, 10 * tol
);
198 // Integrating through zero risks precision loss:
199 Q
= integrator
.integrate(f3
, -10, std::numeric_limits
<Real
>::has_infinity
? std::numeric_limits
<Real
>::infinity() : boost::math::tools::max_value
<Real
>(), get_convergence_tolerance
<Real
>(), &error
, &L1
);
200 Q_expected
= boost::lexical_cast
<Real
>("-15232.3213626280525704332288302799653087046646639974940243044623285817777006");
201 BOOST_CHECK_CLOSE_FRACTION(Q
, Q_expected
, std::numeric_limits
<Real
>::digits10
> 30 ? 1000 * tol
: tol
);
203 auto f4
= [](Real t
)->Real
{ return 1/(1+t
*t
); };
204 Q
= integrator
.integrate(f4
, 1, std::numeric_limits
<Real
>::has_infinity
? std::numeric_limits
<Real
>::infinity() : boost::math::tools::max_value
<Real
>(), get_convergence_tolerance
<Real
>(), &error
, &L1
);
205 Q_expected
= pi
<Real
>()/4;
206 BOOST_CHECK_CLOSE_FRACTION(Q
, Q_expected
, tol
);
207 BOOST_CHECK_CLOSE_FRACTION(L1
, Q_expected
, tol
);
208 Q
= integrator
.integrate(f4
, 20, std::numeric_limits
<Real
>::has_infinity
? std::numeric_limits
<Real
>::infinity() : boost::math::tools::max_value
<Real
>(), get_convergence_tolerance
<Real
>(), &error
, &L1
);
209 Q_expected
= boost::lexical_cast
<Real
>("0.0499583957219427614100062870348448814912770804235071744108534548299835954767");
210 BOOST_CHECK_CLOSE_FRACTION(Q
, Q_expected
, tol
);
211 BOOST_CHECK_CLOSE_FRACTION(L1
, Q_expected
, tol
);
212 Q
= integrator
.integrate(f4
, 500, std::numeric_limits
<Real
>::has_infinity
? std::numeric_limits
<Real
>::infinity() : boost::math::tools::max_value
<Real
>(), get_convergence_tolerance
<Real
>(), &error
, &L1
);
213 Q_expected
= boost::lexical_cast
<Real
>("0.0019999973333397333150476759363217553199063513829126652556286269630");
214 BOOST_CHECK_CLOSE_FRACTION(Q
, Q_expected
, tol
);
215 BOOST_CHECK_CLOSE_FRACTION(L1
, Q_expected
, tol
);
219 void test_left_limit_infinite()
221 std::cout
<< "Testing left limit infinite for 1/(1+t^2) on type " << boost::typeindex::type_id
<Real
>().pretty_name() << "\n";
222 Real tol
= 10 * boost::math::tools::epsilon
<Real
>();
227 auto integrator
= get_integrator
<Real
>();
230 auto f1
= [](const Real
& t
) { return 1/(1+t
*t
);};
231 Q
= integrator
.integrate(f1
, std::numeric_limits
<Real
>::has_infinity
? -std::numeric_limits
<Real
>::infinity() : -boost::math::tools::max_value
<Real
>(), 0, get_convergence_tolerance
<Real
>(), &error
, &L1
);
232 Q_expected
= half_pi
<Real
>();
233 BOOST_CHECK_CLOSE_FRACTION(Q
, Q_expected
, tol
);
234 BOOST_CHECK_CLOSE_FRACTION(L1
, Q_expected
, tol
);
235 Q
= integrator
.integrate(f1
, std::numeric_limits
<Real
>::has_infinity
? -std::numeric_limits
<Real
>::infinity() : -boost::math::tools::max_value
<Real
>(), -20, get_convergence_tolerance
<Real
>(), &error
, &L1
);
236 Q_expected
= boost::lexical_cast
<Real
>("0.0499583957219427614100062870348448814912770804235071744108534548299835954767");
237 BOOST_CHECK_CLOSE_FRACTION(Q
, Q_expected
, tol
);
238 BOOST_CHECK_CLOSE_FRACTION(L1
, Q_expected
, tol
);
239 Q
= integrator
.integrate(f1
, std::numeric_limits
<Real
>::has_infinity
? -std::numeric_limits
<Real
>::infinity() : -boost::math::tools::max_value
<Real
>(), -500, get_convergence_tolerance
<Real
>(), &error
, &L1
);
240 Q_expected
= boost::lexical_cast
<Real
>("0.0019999973333397333150476759363217553199063513829126652556286269630");
241 BOOST_CHECK_CLOSE_FRACTION(Q
, Q_expected
, tol
);
242 BOOST_CHECK_CLOSE_FRACTION(L1
, Q_expected
, tol
);
246 // Some examples of tough integrals from NR, section 4.5.4:
248 void test_nr_examples()
255 std::cout
<< "Testing type " << boost::typeindex::type_id
<Real
>().pretty_name() << "\n";
256 Real tol
= 10 * boost::math::tools::epsilon
<Real
>();
257 std::cout
<< std::setprecision(std::numeric_limits
<Real
>::digits10
);
262 auto integrator
= get_integrator
<Real
>();
264 auto f0
= [] (Real
)->Real
{ return (Real
) 0; };
265 Q
= integrator
.integrate(f0
, get_convergence_tolerance
<Real
>(), &error
, &L1
);
267 BOOST_CHECK_CLOSE_FRACTION(Q
, 0.0f
, tol
);
268 BOOST_CHECK_CLOSE_FRACTION(L1
, 0.0f
, tol
);
270 auto f
= [](const Real
& x
) { return 1/(1+x
*x
); };
271 Q
= integrator
.integrate(f
, get_convergence_tolerance
<Real
>(), &error
, &L1
);
272 Q_expected
= half_pi
<Real
>();
273 BOOST_CHECK_CLOSE_FRACTION(Q
, Q_expected
, tol
);
274 BOOST_CHECK_CLOSE_FRACTION(L1
, Q_expected
, tol
);
276 auto f1
= [](Real x
)->Real
{
282 Real z2
= pow(x
, -3*half
<Real
>())*z1
;
287 return sin(x
*half
<Real
>())*z2
;
290 Q
= integrator
.integrate(f1
, get_convergence_tolerance
<Real
>(), &error
, &L1
);
291 Q_expected
= sqrt(pi
<Real
>()*(sqrt((Real
) 5) - 2));
293 // The integrand is oscillatory; the accuracy is low.
295 if (std::numeric_limits
<Real
>::digits10
> 40)
297 BOOST_CHECK_CLOSE_FRACTION(Q
, Q_expected
, tol_mul
* tol
);
299 auto f2
= [](Real x
)->Real
{ return x
> boost::math::tools::log_max_value
<Real
>() ? Real(0) : Real(pow(x
, -(Real
) 2/(Real
) 7)*exp(-x
*x
)); };
300 Q
= integrator
.integrate(f2
, get_convergence_tolerance
<Real
>(), &error
, &L1
);
301 Q_expected
= half
<Real
>()*boost::math::tgamma((Real
) 5/ (Real
) 14);
303 if (std::numeric_limits
<Real
>::is_specialized
== false)
305 if (std::numeric_limits
<Real
>::digits10
> 40)
307 BOOST_CHECK_CLOSE_FRACTION(Q
, Q_expected
, tol_mul
* tol
);
308 BOOST_CHECK_CLOSE_FRACTION(L1
, Q_expected
, tol_mul
* tol
);
310 auto f3
= [](Real x
)->Real
{ return (Real
) 1/ (sqrt(x
)*(1+x
)); };
311 Q
= integrator
.integrate(f3
, get_convergence_tolerance
<Real
>(), &error
, &L1
);
312 Q_expected
= pi
<Real
>();
314 BOOST_CHECK_CLOSE_FRACTION(Q
, Q_expected
, 10*boost::math::tools::epsilon
<Real
>());
315 BOOST_CHECK_CLOSE_FRACTION(L1
, Q_expected
, 10*boost::math::tools::epsilon
<Real
>());
317 auto f4
= [](const Real
& t
) { return t
> boost::math::tools::log_max_value
<Real
>() ? Real(0) : Real(exp(-t
*t
*half
<Real
>())); };
318 Q
= integrator
.integrate(f4
, get_convergence_tolerance
<Real
>(), &error
, &L1
);
319 Q_expected
= root_two_pi
<Real
>()/2;
321 if (std::numeric_limits
<Real
>::digits10
> 40)
323 BOOST_CHECK_CLOSE_FRACTION(Q
, Q_expected
, tol_mul
* tol
);
324 BOOST_CHECK_CLOSE_FRACTION(L1
, Q_expected
, tol_mul
* tol
);
326 auto f5
= [](const Real
& t
) { return 1/cosh(t
);};
327 Q
= integrator
.integrate(f5
, get_convergence_tolerance
<Real
>(), &error
, &L1
);
328 Q_expected
= half_pi
<Real
>();
329 BOOST_CHECK_CLOSE_FRACTION(Q
, Q_expected
, tol
* 12); // Fails at float precision without higher error rate
330 BOOST_CHECK_CLOSE_FRACTION(L1
, Q_expected
, tol
* 12);
333 // Definite integrals found in the CRC Handbook of Mathematical Formulas
343 std::cout
<< "Testing integral from CRC handbook on type " << boost::typeindex::type_id
<Real
>().pretty_name() << "\n";
344 Real tol
= 10 * boost::math::tools::epsilon
<Real
>();
345 std::cout
<< std::setprecision(std::numeric_limits
<Real
>::digits10
);
350 auto integrator
= get_integrator
<Real
>();
352 auto f0
= [](const Real
& x
) { return x
> boost::math::tools::log_max_value
<Real
>() ? Real(0) : Real(log(x
)*exp(-x
)); };
353 Q
= integrator
.integrate(f0
, get_convergence_tolerance
<Real
>(), &error
, &L1
);
354 Q_expected
= -boost::math::constants::euler
<Real
>();
355 BOOST_CHECK_CLOSE_FRACTION(Q
, Q_expected
, tol
);
357 // Test the integral representation of the gamma function:
358 auto f1
= [](Real t
)->Real
{ Real x
= exp(-t
);
363 return pow(t
, (Real
) 12 - 1)*x
;
366 Q
= integrator
.integrate(f1
, get_convergence_tolerance
<Real
>(), &error
, &L1
);
367 Q_expected
= boost::math::tgamma(12.0f
);
368 BOOST_CHECK_CLOSE_FRACTION(Q
, Q_expected
, tol
);
370 // Integral representation of the modified bessel function:
372 auto f2
= [](Real t
)->Real
{
374 if (x
> boost::math::tools::log_max_value
<Real
>())
378 return exp(-x
)*cosh(5*t
);
380 Q
= integrator
.integrate(f2
, get_convergence_tolerance
<Real
>(), &error
, &L1
);
381 Q_expected
= boost::math::cyl_bessel_k
<int, Real
>(5, 12);
382 BOOST_CHECK_CLOSE_FRACTION(Q
, Q_expected
, tol
);
383 // Laplace transform of cos(at)
386 auto f3
= [&](Real t
)->Real
{
388 if (x
> boost::math::tools::log_max_value
<Real
>())
392 return cos(a
* t
) * exp(-x
);
395 // For high oscillation frequency, the quadrature sum is ill-conditioned.
396 Q
= integrator
.integrate(f3
, get_convergence_tolerance
<Real
>(), &error
, &L1
);
397 Q_expected
= s
/(a
*a
+s
*s
);
398 // Since the integrand is oscillatory, we increase the tolerance:
400 // Multiprecision type have higher error rates, probably evaluation of f() is less accurate:
401 if (!boost::is_class
<Real
>::value
)
403 if (std::numeric_limits
<Real
>::digits10
> std::numeric_limits
<double>::digits10
)
404 tol_mult
= 5000; // we should really investigate this more??
405 BOOST_CHECK_CLOSE_FRACTION(Q
, Q_expected
, tol_mult
*tol
);
409 // This one doesn't pass for real_concept..
411 if (std::numeric_limits
<Real
>::is_specialized
)
413 // Laplace transform of J_0(t):
414 auto f4
= [&](Real t
)->Real
{
416 if (x
> boost::math::tools::log_max_value
<Real
>())
420 return boost::math::cyl_bessel_j(0, t
) * exp(-x
);
423 Q
= integrator
.integrate(f4
, get_convergence_tolerance
<Real
>(), &error
, &L1
);
424 Q_expected
= 1 / sqrt(1 + s
*s
);
426 // Multiprecision type have higher error rates, probably evaluation of f() is less accurate:
427 if (std::numeric_limits
<Real
>::digits10
> std::numeric_limits
<long double>::digits10
)
429 BOOST_CHECK_CLOSE_FRACTION(Q
, Q_expected
, tol_mult
* tol
);
431 auto f6
= [](const Real
& t
) { return t
> boost::math::tools::log_max_value
<Real
>() ? Real(0) : Real(exp(-t
*t
)*log(t
));};
432 Q
= integrator
.integrate(f6
, get_convergence_tolerance
<Real
>(), &error
, &L1
);
433 Q_expected
= -boost::math::constants::root_pi
<Real
>()*(boost::math::constants::euler
<Real
>() + 2*ln_two
<Real
>())/4;
434 BOOST_CHECK_CLOSE_FRACTION(Q
, Q_expected
, tol
);
436 // CRC Section 5.5, integral 591
437 // The parameter p allows us to control the strength of the singularity.
438 // Rapid convergence is not guaranteed for this function, as the branch cut makes it non-analytic on a disk.
439 // This converges only when our test type has an extended exponent range as all the area of the integral
440 // occurs so close to 0 (or 1) that we need abscissa values exceptionally small to find it.
441 // "There's a lot of room at the bottom".
442 // This version is transformed via argument substitution (exp(-x) for x) so that the integral is spread
444 tol
*= boost::math::tools::digits
<Real
>() > 100 ? 100000 : 75;
445 for (Real pn
= 99; pn
> 0; pn
-= 10) {
447 auto f
= [&](Real x
)->Real
449 return x
> 1000 * boost::math::tools::log_max_value
<Real
>() ? Real(0) : Real(exp(-x
* (1 - p
) + p
* log(-boost::math::expm1(-x
))));
451 Q
= integrator
.integrate(f
, get_convergence_tolerance
<Real
>(), &error
, &L1
);
452 Q_expected
= 1 / boost::math::sinc_pi(p
*pi
<Real
>());
454 std::cout << std::setprecision(std::numeric_limits<Real>::max_digits10) << p << std::endl;
455 std::cout << std::setprecision(std::numeric_limits<Real>::max_digits10) << Q << std::endl;
456 std::cout << std::setprecision(std::numeric_limits<Real>::max_digits10) << Q_expected << std::endl;
457 std::cout << fabs((Q - Q_expected) / Q_expected) << std::endl;
459 BOOST_CHECK_CLOSE_FRACTION(Q
, Q_expected
, tol
);
462 for (Real p
= -0.99; p
< 0; p
+= 0.1) {
463 auto f
= [&](Real x
)->Real
465 return x
> 1000 * boost::math::tools::log_max_value
<Real
>() ? Real(0) : Real(exp(-p
* log(-boost::math::expm1(-x
)) - (1 + p
) * x
));
467 Q
= integrator
.integrate(f
, get_convergence_tolerance
<Real
>(), &error
, &L1
);
468 Q_expected
= 1 / boost::math::sinc_pi(p
*pi
<Real
>());
469 BOOST_CHECK_CLOSE_FRACTION(Q
, Q_expected
, tol
);
474 BOOST_AUTO_TEST_CASE(exp_sinh_quadrature_test
)
477 // Uncomment to generate the coefficients:
481 std::cout << std::scientific << std::setprecision(8);
482 print_levels(generate_constants<cpp_bin_float_100, float>(8), "f");
483 std::cout << std::setprecision(18);
484 print_levels(generate_constants<cpp_bin_float_100, double>(8), "");
485 std::cout << std::setprecision(35);
486 print_levels(generate_constants<cpp_bin_float_100, cpp_bin_float_quad>(8), "L");
491 test_left_limit_infinite
<float>();
492 test_right_limit_infinite
<float>();
493 test_nr_examples
<float>();
497 test_left_limit_infinite
<double>();
498 test_right_limit_infinite
<double>();
499 test_nr_examples
<double>();
503 test_left_limit_infinite
<long double>();
504 test_right_limit_infinite
<long double>();
505 test_nr_examples
<long double>();
506 test_crc
<long double>();
509 test_left_limit_infinite
<cpp_bin_float_quad
>();
510 test_right_limit_infinite
<cpp_bin_float_quad
>();
511 test_nr_examples
<cpp_bin_float_quad
>();
512 test_crc
<cpp_bin_float_quad
>();
516 test_left_limit_infinite
<boost::math::concepts::real_concept
>();
517 test_right_limit_infinite
<boost::math::concepts::real_concept
>();
518 test_nr_examples
<boost::math::concepts::real_concept
>();
519 test_crc
<boost::math::concepts::real_concept
>();
523 test_left_limit_infinite
<boost::multiprecision::cpp_bin_float_50
>();
524 test_right_limit_infinite
<boost::multiprecision::cpp_bin_float_50
>();
525 test_nr_examples
<boost::multiprecision::cpp_bin_float_50
>();
526 test_crc
<boost::multiprecision::cpp_bin_float_50
>();
529 test_left_limit_infinite
<boost::multiprecision::cpp_dec_float_50
>();
530 test_right_limit_infinite
<boost::multiprecision::cpp_dec_float_50
>();
531 test_nr_examples
<boost::multiprecision::cpp_dec_float_50
>();
532 test_crc
<boost::multiprecision::cpp_dec_float_50
>();