ellint_2.hpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. // Copyright (c) 2006 Xiaogang Zhang
  2. // Copyright (c) 2006 John Maddock
  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. // History:
  8. // XZ wrote the original of this file as part of the Google
  9. // Summer of Code 2006. JM modified it to fit into the
  10. // Boost.Math conceptual framework better, and to ensure
  11. // that the code continues to work no matter how many digits
  12. // type T has.
  13. #ifndef BOOST_MATH_ELLINT_2_HPP
  14. #define BOOST_MATH_ELLINT_2_HPP
  15. #ifdef _MSC_VER
  16. #pragma once
  17. #endif
  18. #include <boost/math/special_functions/ellint_rf.hpp>
  19. #include <boost/math/special_functions/ellint_rd.hpp>
  20. #include <boost/math/constants/constants.hpp>
  21. #include <boost/math/policies/error_handling.hpp>
  22. #include <boost/math/tools/workaround.hpp>
  23. #include <boost/math/special_functions/round.hpp>
  24. // Elliptic integrals (complete and incomplete) of the second kind
  25. // Carlson, Numerische Mathematik, vol 33, 1 (1979)
  26. namespace boost { namespace math {
  27. template <class T1, class T2, class Policy>
  28. typename tools::promote_args<T1, T2>::type ellint_2(T1 k, T2 phi, const Policy& pol);
  29. namespace detail{
  30. template <typename T, typename Policy>
  31. T ellint_e_imp(T k, const Policy& pol);
  32. // Elliptic integral (Legendre form) of the second kind
  33. template <typename T, typename Policy>
  34. T ellint_e_imp(T phi, T k, const Policy& pol)
  35. {
  36. BOOST_MATH_STD_USING
  37. using namespace boost::math::tools;
  38. using namespace boost::math::constants;
  39. bool invert = false;
  40. if(phi < 0)
  41. {
  42. phi = fabs(phi);
  43. invert = true;
  44. }
  45. T result;
  46. if(phi >= tools::max_value<T>())
  47. {
  48. // Need to handle infinity as a special case:
  49. result = policies::raise_overflow_error<T>("boost::math::ellint_e<%1%>(%1%,%1%)", 0, pol);
  50. }
  51. else if(phi > 1 / tools::epsilon<T>())
  52. {
  53. // Phi is so large that phi%pi is necessarily zero (or garbage),
  54. // just return the second part of the duplication formula:
  55. result = 2 * phi * ellint_e_imp(k, pol) / constants::pi<T>();
  56. }
  57. else
  58. {
  59. // Carlson's algorithm works only for |phi| <= pi/2,
  60. // use the integrand's periodicity to normalize phi
  61. //
  62. // Xiaogang's original code used a cast to long long here
  63. // but that fails if T has more digits than a long long,
  64. // so rewritten to use fmod instead:
  65. //
  66. T rphi = boost::math::tools::fmod_workaround(phi, T(constants::half_pi<T>()));
  67. T m = boost::math::round((phi - rphi) / constants::half_pi<T>());
  68. int s = 1;
  69. if(boost::math::tools::fmod_workaround(m, T(2)) > 0.5)
  70. {
  71. m += 1;
  72. s = -1;
  73. rphi = constants::half_pi<T>() - rphi;
  74. }
  75. T sinp = sin(rphi);
  76. T cosp = cos(rphi);
  77. T x = cosp * cosp;
  78. T t = k * k * sinp * sinp;
  79. T y = 1 - t;
  80. T z = 1;
  81. result = s * sinp * (ellint_rf_imp(x, y, z, pol) - t * ellint_rd_imp(x, y, z, pol) / 3);
  82. if(m != 0)
  83. result += m * ellint_e_imp(k, pol);
  84. }
  85. return invert ? T(-result) : result;
  86. }
  87. // Complete elliptic integral (Legendre form) of the second kind
  88. template <typename T, typename Policy>
  89. T ellint_e_imp(T k, const Policy& pol)
  90. {
  91. BOOST_MATH_STD_USING
  92. using namespace boost::math::tools;
  93. if (abs(k) > 1)
  94. {
  95. return policies::raise_domain_error<T>("boost::math::ellint_e<%1%>(%1%)",
  96. "Got k = %1%, function requires |k| <= 1", k, pol);
  97. }
  98. if (abs(k) == 1)
  99. {
  100. return static_cast<T>(1);
  101. }
  102. T x = 0;
  103. T t = k * k;
  104. T y = 1 - t;
  105. T z = 1;
  106. T value = ellint_rf_imp(x, y, z, pol) - t * ellint_rd_imp(x, y, z, pol) / 3;
  107. return value;
  108. }
  109. template <typename T, typename Policy>
  110. inline typename tools::promote_args<T>::type ellint_2(T k, const Policy& pol, const mpl::true_&)
  111. {
  112. typedef typename tools::promote_args<T>::type result_type;
  113. typedef typename policies::evaluation<result_type, Policy>::type value_type;
  114. return policies::checked_narrowing_cast<result_type, Policy>(detail::ellint_e_imp(static_cast<value_type>(k), pol), "boost::math::ellint_2<%1%>(%1%)");
  115. }
  116. // Elliptic integral (Legendre form) of the second kind
  117. template <class T1, class T2>
  118. inline typename tools::promote_args<T1, T2>::type ellint_2(T1 k, T2 phi, const mpl::false_&)
  119. {
  120. return boost::math::ellint_2(k, phi, policies::policy<>());
  121. }
  122. } // detail
  123. // Complete elliptic integral (Legendre form) of the second kind
  124. template <typename T>
  125. inline typename tools::promote_args<T>::type ellint_2(T k)
  126. {
  127. return ellint_2(k, policies::policy<>());
  128. }
  129. // Elliptic integral (Legendre form) of the second kind
  130. template <class T1, class T2>
  131. inline typename tools::promote_args<T1, T2>::type ellint_2(T1 k, T2 phi)
  132. {
  133. typedef typename policies::is_policy<T2>::type tag_type;
  134. return detail::ellint_2(k, phi, tag_type());
  135. }
  136. template <class T1, class T2, class Policy>
  137. inline typename tools::promote_args<T1, T2>::type ellint_2(T1 k, T2 phi, const Policy& pol)
  138. {
  139. typedef typename tools::promote_args<T1, T2>::type result_type;
  140. typedef typename policies::evaluation<result_type, Policy>::type value_type;
  141. return policies::checked_narrowing_cast<result_type, Policy>(detail::ellint_e_imp(static_cast<value_type>(phi), static_cast<value_type>(k), pol), "boost::math::ellint_2<%1%>(%1%,%1%)");
  142. }
  143. }} // namespaces
  144. #endif // BOOST_MATH_ELLINT_2_HPP