test_recurrence.cpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  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)
  5. #define BOOST_TEST_MODULE test_recurrences
  6. #include <boost/config.hpp>
  7. #ifndef BOOST_NO_CXX11_HDR_TUPLE
  8. #include <boost/multiprecision/cpp_bin_float.hpp>
  9. #include <boost/math/tools/recurrence.hpp>
  10. #include <boost/math/special_functions/bessel.hpp>
  11. #include <boost/test/included/unit_test.hpp>
  12. #include <boost/test/floating_point_comparison.hpp>
  13. //#include <boost/test/tools/floating_point_comparison.hpp>
  14. #include <boost/math/concepts/real_concept.hpp>
  15. #ifdef BOOST_MSVC
  16. #pragma warning(disable:4127)
  17. #endif
  18. template <class T>
  19. struct bessel_jy_recurrence
  20. {
  21. bessel_jy_recurrence(T v, T z) : v(v), z(z) {}
  22. boost::math::tuple<T, T, T> operator()(int k)const
  23. {
  24. return boost::math::tuple<T, T, T>(T(1), -2 * (v + k) / z, T(1));
  25. }
  26. T v, z;
  27. };
  28. template <class T>
  29. struct bessel_ik_recurrence
  30. {
  31. bessel_ik_recurrence(T v, T z) : v(v), z(z) {}
  32. boost::math::tuple<T, T, T> operator()(int k)const
  33. {
  34. return boost::math::tuple<T, T, T>(T(1), -2 * (v + k) / z, T(-1));
  35. }
  36. T v, z;
  37. };
  38. template <class T>
  39. void test_spots(T, const char* name)
  40. {
  41. std::cout << "Running tests for type " << name << std::endl;
  42. T tol = boost::math::tools::epsilon<T>() * 5;
  43. if ((std::numeric_limits<T>::digits > 53) || (std::numeric_limits<T>::digits == 0))
  44. tol *= 5;
  45. //
  46. // Test forward recurrence on Y_v(x):
  47. //
  48. {
  49. T v = 22.25;
  50. T x = 4.125;
  51. bessel_jy_recurrence<T> coef(v, x);
  52. T prev;
  53. T first = boost::math::cyl_neumann(v - 1, x);
  54. T second = boost::math::cyl_neumann(v, x);
  55. T sixth = boost::math::tools::apply_recurrence_relation_forward(coef, 6, first, second, (int*)0, &prev);
  56. T expected1 = boost::math::cyl_neumann(v + 6, x);
  57. T expected2 = boost::math::cyl_neumann(v + 5, x);
  58. BOOST_CHECK_CLOSE_FRACTION(sixth, expected1, tol);
  59. BOOST_CHECK_CLOSE_FRACTION(prev, expected2, tol);
  60. boost::math::tools::forward_recurrence_iterator< bessel_jy_recurrence<T> > it(coef, first, second);
  61. for (unsigned i = 0; i < 15; ++i)
  62. {
  63. expected1 = boost::math::cyl_neumann(v + i, x);
  64. T found = *it;
  65. BOOST_CHECK_CLOSE_FRACTION(found, expected1, tol);
  66. ++it;
  67. }
  68. if (std::numeric_limits<T>::max_exponent > 300)
  69. {
  70. //
  71. // This calculates the ratio Y_v(x)/Y_v+1(x) from the recurrence relations
  72. // which are only transiently stable since Y_v is not minimal as v->-INF
  73. // but only as v->0. We have to be sure that v is sufficiently large that
  74. // convergence is complete before we reach the origin.
  75. //
  76. v = 102.75;
  77. boost::uintmax_t max_iter = 200;
  78. T ratio = boost::math::tools::function_ratio_from_forwards_recurrence(bessel_jy_recurrence<T>(v, x), boost::math::tools::epsilon<T>(), max_iter);
  79. first = boost::math::cyl_neumann(v, x);
  80. second = boost::math::cyl_neumann(v + 1, x);
  81. BOOST_CHECK_CLOSE_FRACTION(ratio, first / second, tol);
  82. boost::math::tools::forward_recurrence_iterator< bessel_jy_recurrence<T> > it2(bessel_jy_recurrence<T>(v, x), boost::math::cyl_neumann(v, x));
  83. for (unsigned i = 0; i < 15; ++i)
  84. {
  85. expected1 = boost::math::cyl_neumann(v + i, x);
  86. T found = *it2;
  87. BOOST_CHECK_CLOSE_FRACTION(found, expected1, tol);
  88. ++it2;
  89. }
  90. }
  91. }
  92. //
  93. // Test backward recurrence on J_v(x):
  94. //
  95. {
  96. if ((std::numeric_limits<T>::digits > 53) || !std::numeric_limits<T>::is_specialized)
  97. tol *= 5;
  98. T v = 22.25;
  99. T x = 4.125;
  100. bessel_jy_recurrence<T> coef(v, x);
  101. T prev;
  102. T first = boost::math::cyl_bessel_j(v + 1, x);
  103. T second = boost::math::cyl_bessel_j(v, x);
  104. T sixth = boost::math::tools::apply_recurrence_relation_backward(coef, 6, first, second, (int*)0, &prev);
  105. T expected1 = boost::math::cyl_bessel_j(v - 6, x);
  106. T expected2 = boost::math::cyl_bessel_j(v - 5, x);
  107. BOOST_CHECK_CLOSE_FRACTION(sixth, expected1, tol);
  108. BOOST_CHECK_CLOSE_FRACTION(prev, expected2, tol);
  109. boost::math::tools::backward_recurrence_iterator< bessel_jy_recurrence<T> > it(coef, first, second);
  110. for (unsigned i = 0; i < 15; ++i)
  111. {
  112. expected1 = boost::math::cyl_bessel_j(v - i, x);
  113. T found = *it;
  114. BOOST_CHECK_CLOSE_FRACTION(found, expected1, tol);
  115. ++it;
  116. }
  117. boost::uintmax_t max_iter = 200;
  118. T ratio = boost::math::tools::function_ratio_from_backwards_recurrence(bessel_jy_recurrence<T>(v, x), boost::math::tools::epsilon<T>(), max_iter);
  119. first = boost::math::cyl_bessel_j(v, x);
  120. second = boost::math::cyl_bessel_j(v - 1, x);
  121. BOOST_CHECK_CLOSE_FRACTION(ratio, first / second, tol);
  122. boost::math::tools::backward_recurrence_iterator< bessel_jy_recurrence<T> > it2(bessel_jy_recurrence<T>(v, x), boost::math::cyl_bessel_j(v, x));
  123. //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));
  124. for (unsigned i = 0; i < 15; ++i)
  125. {
  126. expected1 = boost::math::cyl_bessel_j(v - i, x);
  127. T found = *it2;
  128. BOOST_CHECK_CLOSE_FRACTION(found, expected1, tol);
  129. ++it2;
  130. }
  131. }
  132. }
  133. BOOST_AUTO_TEST_CASE( test_main )
  134. {
  135. BOOST_MATH_CONTROL_FP;
  136. #if !defined(TEST) || TEST == 1
  137. test_spots(0.0F, "float");
  138. test_spots(0.0, "double");
  139. #ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
  140. test_spots(0.0L, "long double");
  141. #ifndef BOOST_MATH_NO_REAL_CONCEPT_TESTS
  142. test_spots(boost::math::concepts::real_concept(0.1), "real_concept");
  143. #endif
  144. #endif
  145. #endif
  146. #if !defined(TEST) || TEST == 2 || TEST == 3
  147. test_spots(boost::multiprecision::cpp_bin_float_quad(), "cpp_bin_float_quad");
  148. #endif
  149. }
  150. #else
  151. int main() { return 0; }
  152. #endif