1 // (C) Copyright John Maddock 2018.
2 // Use, modification and distribution are subject to the
3 // Boost Software License, Version 1.0. (See accompanying file
4 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 #define BOOST_TEST_MODULE test_recurrences
8 #include <boost/config.hpp>
10 #ifndef BOOST_NO_CXX11_HDR_TUPLE
11 #include <boost/multiprecision/cpp_bin_float.hpp>
12 #include <boost/math/tools/recurrence.hpp>
13 #include <boost/math/special_functions/bessel.hpp>
14 #include <boost/test/included/unit_test.hpp>
15 #include <boost/test/floating_point_comparison.hpp>
16 //#include <boost/test/tools/floating_point_comparison.hpp>
17 #include <boost/math/concepts/real_concept.hpp>
20 #pragma warning(disable:4127)
24 struct bessel_jy_recurrence
26 bessel_jy_recurrence(T v, T z) : v(v), z(z) {}
27 boost::math::tuple<T, T, T> operator()(int k)const
29 return boost::math::tuple<T, T, T>(T(1), -2 * (v + k) / z, T(1));
36 struct bessel_ik_recurrence
38 bessel_ik_recurrence(T v, T z) : v(v), z(z) {}
39 boost::math::tuple<T, T, T> operator()(int k)const
41 return boost::math::tuple<T, T, T>(T(1), -2 * (v + k) / z, T(-1));
49 void test_spots(T, const char* name)
51 std::cout << "Running tests for type " << name << std::endl;
52 T tol = boost::math::tools::epsilon<T>() * 5;
53 if ((std::numeric_limits<T>::digits > 53) || (std::numeric_limits<T>::digits == 0))
56 // Test forward recurrence on Y_v(x):
61 bessel_jy_recurrence<T> coef(v, x);
63 T first = boost::math::cyl_neumann(v - 1, x);
64 T second = boost::math::cyl_neumann(v, x);
65 T sixth = boost::math::tools::apply_recurrence_relation_forward(coef, 6, first, second, (int*)0, &prev);
66 T expected1 = boost::math::cyl_neumann(v + 6, x);
67 T expected2 = boost::math::cyl_neumann(v + 5, x);
68 BOOST_CHECK_CLOSE_FRACTION(sixth, expected1, tol);
69 BOOST_CHECK_CLOSE_FRACTION(prev, expected2, tol);
71 boost::math::tools::forward_recurrence_iterator< bessel_jy_recurrence<T> > it(coef, first, second);
72 for (unsigned i = 0; i < 15; ++i)
74 expected1 = boost::math::cyl_neumann(v + i, x);
76 BOOST_CHECK_CLOSE_FRACTION(found, expected1, tol);
80 if (std::numeric_limits<T>::max_exponent > 300)
83 // This calculates the ratio Y_v(x)/Y_v+1(x) from the recurrence relations
84 // which are only transiently stable since Y_v is not minimal as v->-INF
85 // but only as v->0. We have to be sure that v is sufficiently large that
86 // convergence is complete before we reach the origin.
89 boost::uintmax_t max_iter = 200;
90 T ratio = boost::math::tools::function_ratio_from_forwards_recurrence(bessel_jy_recurrence<T>(v, x), boost::math::tools::epsilon<T>(), max_iter);
91 first = boost::math::cyl_neumann(v, x);
92 second = boost::math::cyl_neumann(v + 1, x);
93 BOOST_CHECK_CLOSE_FRACTION(ratio, first / second, tol);
95 boost::math::tools::forward_recurrence_iterator< bessel_jy_recurrence<T> > it2(bessel_jy_recurrence<T>(v, x), boost::math::cyl_neumann(v, x));
96 for (unsigned i = 0; i < 15; ++i)
98 expected1 = boost::math::cyl_neumann(v + i, x);
100 BOOST_CHECK_CLOSE_FRACTION(found, expected1, tol);
107 // Test backward recurrence on J_v(x):
110 if ((std::numeric_limits<T>::digits > 53) || !std::numeric_limits<T>::is_specialized)
115 bessel_jy_recurrence<T> coef(v, x);
117 T first = boost::math::cyl_bessel_j(v + 1, x);
118 T second = boost::math::cyl_bessel_j(v, x);
119 T sixth = boost::math::tools::apply_recurrence_relation_backward(coef, 6, first, second, (int*)0, &prev);
120 T expected1 = boost::math::cyl_bessel_j(v - 6, x);
121 T expected2 = boost::math::cyl_bessel_j(v - 5, x);
122 BOOST_CHECK_CLOSE_FRACTION(sixth, expected1, tol);
123 BOOST_CHECK_CLOSE_FRACTION(prev, expected2, tol);
125 boost::math::tools::backward_recurrence_iterator< bessel_jy_recurrence<T> > it(coef, first, second);
126 for (unsigned i = 0; i < 15; ++i)
128 expected1 = boost::math::cyl_bessel_j(v - i, x);
130 BOOST_CHECK_CLOSE_FRACTION(found, expected1, tol);
134 boost::uintmax_t max_iter = 200;
135 T ratio = boost::math::tools::function_ratio_from_backwards_recurrence(bessel_jy_recurrence<T>(v, x), boost::math::tools::epsilon<T>(), max_iter);
136 first = boost::math::cyl_bessel_j(v, x);
137 second = boost::math::cyl_bessel_j(v - 1, x);
138 BOOST_CHECK_CLOSE_FRACTION(ratio, first / second, tol);
140 boost::math::tools::backward_recurrence_iterator< bessel_jy_recurrence<T> > it2(bessel_jy_recurrence<T>(v, x), boost::math::cyl_bessel_j(v, x));
141 //boost::math::tools::backward_recurrence_iterator< bessel_jy_recurrence<T> > it3(bessel_jy_recurrence<T>(v, x), boost::math::cyl_neumann(v+1, x), boost::math::cyl_neumann(v, x));
142 for (unsigned i = 0; i < 15; ++i)
144 expected1 = boost::math::cyl_bessel_j(v - i, x);
146 BOOST_CHECK_CLOSE_FRACTION(found, expected1, tol);
154 BOOST_AUTO_TEST_CASE( test_main )
156 BOOST_MATH_CONTROL_FP;
157 #if !defined(TEST) || TEST == 1
158 test_spots(0.0F, "float");
159 test_spots(0.0, "double");
160 #ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
161 test_spots(0.0L, "long double");
162 #ifndef BOOST_MATH_NO_REAL_CONCEPT_TESTS
163 test_spots(boost::math::concepts::real_concept(0.1), "real_concept");
167 #if !defined(TEST) || TEST == 2 || TEST == 3
168 test_spots(boost::multiprecision::cpp_bin_float_quad(), "cpp_bin_float_quad");
174 int main() { return 0; }