chebyshev_test.cpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. /*
  2. * Copyright Nick Thompson, 2017
  3. * Use, modification and distribution are subject to the
  4. * Boost Software License, Version 1.0. (See accompanying file
  5. * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. */
  7. #define BOOST_TEST_MODULE chebyshev_test
  8. #include <boost/type_index.hpp>
  9. #include <boost/test/included/unit_test.hpp>
  10. #include <boost/test/tools/floating_point_comparison.hpp>
  11. #include <boost/math/special_functions/chebyshev.hpp>
  12. #include <boost/math/special_functions/sinc.hpp>
  13. #include <boost/multiprecision/cpp_bin_float.hpp>
  14. #include <boost/multiprecision/cpp_dec_float.hpp>
  15. #include <boost/array.hpp>
  16. using boost::multiprecision::cpp_bin_float_quad;
  17. using boost::multiprecision::cpp_bin_float_50;
  18. using boost::multiprecision::cpp_bin_float_100;
  19. using boost::math::chebyshev_t;
  20. using boost::math::chebyshev_t_prime;
  21. using boost::math::chebyshev_u;
  22. template<class Real>
  23. void test_polynomials()
  24. {
  25. std::cout << "Testing explicit polynomial representations of the Chebyshev polynomials on type " << boost::typeindex::type_id<Real>().pretty_name() << "\n";
  26. Real x = -2;
  27. Real tol = 400*std::numeric_limits<Real>::epsilon();
  28. if (tol > std::numeric_limits<float>::epsilon())
  29. tol *= 10; // float results have much larger error rates.
  30. while (x < 2)
  31. {
  32. BOOST_CHECK_CLOSE_FRACTION(chebyshev_t(0, x), Real(1), tol);
  33. BOOST_CHECK_CLOSE_FRACTION(chebyshev_t(1, x), x, tol);
  34. BOOST_CHECK_CLOSE_FRACTION(chebyshev_t(2, x), 2*x*x - 1, tol);
  35. BOOST_CHECK_CLOSE_FRACTION(chebyshev_t(3, x), x*(4*x*x-3), tol);
  36. BOOST_CHECK_CLOSE_FRACTION(chebyshev_t(4, x), 8*x*x*(x*x - 1) + 1, tol);
  37. BOOST_CHECK_CLOSE_FRACTION(chebyshev_t(5, x), x*(16*x*x*x*x - 20*x*x + 5), tol);
  38. x += 1/static_cast<Real>(1<<7);
  39. }
  40. x = -2;
  41. tol = 10*tol;
  42. while (x < 2)
  43. {
  44. BOOST_CHECK_CLOSE_FRACTION(chebyshev_u(0, x), Real(1), tol);
  45. BOOST_CHECK_CLOSE_FRACTION(chebyshev_u(1, x), 2*x, tol);
  46. BOOST_CHECK_CLOSE_FRACTION(chebyshev_u(2, x), 4*x*x - 1, tol);
  47. BOOST_CHECK_CLOSE_FRACTION(chebyshev_u(3, x), 4*x*(2*x*x - 1), tol);
  48. x += 1/static_cast<Real>(1<<7);
  49. }
  50. }
  51. template<class Real>
  52. void test_derivatives()
  53. {
  54. std::cout << "Testing explicit polynomial representations of the Chebyshev polynomial derivatives on type " << boost::typeindex::type_id<Real>().pretty_name() << "\n";
  55. Real x = -2;
  56. Real tol = 1000*std::numeric_limits<Real>::epsilon();
  57. while (x < 2)
  58. {
  59. BOOST_CHECK_CLOSE_FRACTION(chebyshev_t_prime(0, x), Real(0), tol);
  60. BOOST_CHECK_CLOSE_FRACTION(chebyshev_t_prime(1, x), Real(1), tol);
  61. BOOST_CHECK_CLOSE_FRACTION(chebyshev_t_prime(2, x), 4*x, tol);
  62. BOOST_CHECK_CLOSE_FRACTION(chebyshev_t_prime(3, x), 3*(4*x*x - 1), tol);
  63. BOOST_CHECK_CLOSE_FRACTION(chebyshev_t_prime(4, x), 16*x*(2*x*x - 1), tol);
  64. // This one makes the tolerance have to grow too large; the Chebyshev recurrence is more stable than naive polynomial evaluation anyway.
  65. //BOOST_CHECK_CLOSE_FRACTION(chebyshev_t_prime(5, x), 5*(4*x*x*(4*x*x - 3) + 1), tol);
  66. x += 1/static_cast<Real>(1<<7);
  67. }
  68. }
  69. template<class Real>
  70. void test_clenshaw_recurrence()
  71. {
  72. using boost::math::chebyshev_clenshaw_recurrence;
  73. boost::array<Real, 5> c0 = { {2, 0, 0, 0, 0} };
  74. // Check the size = 1 case:
  75. boost::array<Real, 1> c01 = { {2} };
  76. // Check the size = 2 case:
  77. boost::array<Real, 2> c02 = { {2, 0} };
  78. boost::array<Real, 4> c1 = { {0, 1, 0, 0} };
  79. boost::array<Real, 4> c2 = { {0, 0, 1, 0} };
  80. boost::array<Real, 5> c3 = { {0, 0, 0, 1, 0} };
  81. boost::array<Real, 5> c4 = { {0, 0, 0, 0, 1} };
  82. boost::array<Real, 6> c5 = { {0, 0, 0, 0, 0, 1} };
  83. boost::array<Real, 7> c6 = { {0, 0, 0, 0, 0, 0, 1} };
  84. Real x = -1;
  85. Real tol = 10*std::numeric_limits<Real>::epsilon();
  86. if (tol > std::numeric_limits<float>::epsilon())
  87. tol *= 100; // float results have much larger error rates.
  88. while (x <= 1)
  89. {
  90. Real y = chebyshev_clenshaw_recurrence(c0.data(), c0.size(), x);
  91. BOOST_CHECK_CLOSE_FRACTION(y, chebyshev_t(0, x), tol);
  92. y = chebyshev_clenshaw_recurrence(c01.data(), c01.size(), x);
  93. BOOST_CHECK_CLOSE_FRACTION(y, chebyshev_t(0, x), tol);
  94. y = chebyshev_clenshaw_recurrence(c02.data(), c02.size(), x);
  95. BOOST_CHECK_CLOSE_FRACTION(y, chebyshev_t(0, x), tol);
  96. y = chebyshev_clenshaw_recurrence(c1.data(), c1.size(), x);
  97. BOOST_CHECK_CLOSE_FRACTION(y, chebyshev_t(1, x), tol);
  98. y = chebyshev_clenshaw_recurrence(c2.data(), c2.size(), x);
  99. BOOST_CHECK_CLOSE_FRACTION(y, chebyshev_t(2, x), tol);
  100. y = chebyshev_clenshaw_recurrence(c3.data(), c3.size(), x);
  101. BOOST_CHECK_CLOSE_FRACTION(y, chebyshev_t(3, x), tol);
  102. y = chebyshev_clenshaw_recurrence(c4.data(), c4.size(), x);
  103. BOOST_CHECK_CLOSE_FRACTION(y, chebyshev_t(4, x), tol);
  104. y = chebyshev_clenshaw_recurrence(c5.data(), c5.size(), x);
  105. BOOST_CHECK_CLOSE_FRACTION(y, chebyshev_t(5, x), tol);
  106. y = chebyshev_clenshaw_recurrence(c6.data(), c6.size(), x);
  107. BOOST_CHECK_CLOSE_FRACTION(y, chebyshev_t(6, x), tol);
  108. x += static_cast<Real>(1)/static_cast<Real>(1 << 7);
  109. }
  110. }
  111. BOOST_AUTO_TEST_CASE(chebyshev_test)
  112. {
  113. test_clenshaw_recurrence<float>();
  114. test_clenshaw_recurrence<double>();
  115. test_clenshaw_recurrence<long double>();
  116. test_polynomials<float>();
  117. test_polynomials<double>();
  118. test_polynomials<long double>();
  119. test_polynomials<cpp_bin_float_quad>();
  120. test_derivatives<float>();
  121. test_derivatives<double>();
  122. test_derivatives<long double>();
  123. test_derivatives<cpp_bin_float_quad>();
  124. }