ellint_rf.hpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. // Copyright (c) 2006 Xiaogang Zhang, 2015 John Maddock
  2. // Copyright (c) 2024 Matt Borland
  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 handle
  11. // types longer than 80-bit reals.
  12. // Updated 2015 to use Carlson's latest methods.
  13. //
  14. #ifndef BOOST_MATH_ELLINT_RF_HPP
  15. #define BOOST_MATH_ELLINT_RF_HPP
  16. #ifdef _MSC_VER
  17. #pragma once
  18. #endif
  19. #include <boost/math/tools/config.hpp>
  20. #include <boost/math/tools/numeric_limits.hpp>
  21. #include <boost/math/special_functions/math_fwd.hpp>
  22. #include <boost/math/constants/constants.hpp>
  23. #include <boost/math/policies/error_handling.hpp>
  24. #include <boost/math/special_functions/ellint_rc.hpp>
  25. // Carlson's elliptic integral of the first kind
  26. // R_F(x, y, z) = 0.5 * \int_{0}^{\infty} [(t+x)(t+y)(t+z)]^{-1/2} dt
  27. // Carlson, Numerische Mathematik, vol 33, 1 (1979)
  28. namespace boost { namespace math { namespace detail{
  29. template <typename T, typename Policy>
  30. BOOST_MATH_GPU_ENABLED T ellint_rf_imp(T x, T y, T z, const Policy& pol)
  31. {
  32. BOOST_MATH_STD_USING
  33. using namespace boost::math;
  34. constexpr auto function = "boost::math::ellint_rf<%1%>(%1%,%1%,%1%)";
  35. if(x < 0 || y < 0 || z < 0)
  36. {
  37. return policies::raise_domain_error<T>(function, "domain error, all arguments must be non-negative, only sensible result is %1%.", boost::math::numeric_limits<T>::quiet_NaN(), pol);
  38. }
  39. if(x + y == 0 || y + z == 0 || z + x == 0)
  40. {
  41. return policies::raise_domain_error<T>(function, "domain error, at most one argument can be zero, only sensible result is %1%.", boost::math::numeric_limits<T>::quiet_NaN(), pol);
  42. }
  43. //
  44. // Special cases from http://dlmf.nist.gov/19.20#i
  45. //
  46. if(x == y)
  47. {
  48. if(x == z)
  49. {
  50. // x, y, z equal:
  51. return 1 / sqrt(x);
  52. }
  53. else
  54. {
  55. // 2 equal, x and y:
  56. if(z == 0)
  57. return constants::pi<T>() / (2 * sqrt(x));
  58. else
  59. return ellint_rc_imp(z, x, pol);
  60. }
  61. }
  62. if(x == z)
  63. {
  64. if(y == 0)
  65. return constants::pi<T>() / (2 * sqrt(x));
  66. else
  67. return ellint_rc_imp(y, x, pol);
  68. }
  69. if(y == z)
  70. {
  71. if(x == 0)
  72. return constants::pi<T>() / (2 * sqrt(y));
  73. else
  74. return ellint_rc_imp(x, y, pol);
  75. }
  76. if(x == 0)
  77. BOOST_MATH_GPU_SAFE_SWAP(x, z);
  78. else if(y == 0)
  79. BOOST_MATH_GPU_SAFE_SWAP(y, z);
  80. if(z == 0)
  81. {
  82. //
  83. // Special case for one value zero:
  84. //
  85. T xn = sqrt(x);
  86. T yn = sqrt(y);
  87. while(fabs(xn - yn) >= T(2.7) * tools::root_epsilon<T>() * fabs(xn))
  88. {
  89. T t = sqrt(xn * yn);
  90. xn = (xn + yn) / 2;
  91. yn = t;
  92. }
  93. return constants::pi<T>() / (xn + yn);
  94. }
  95. T xn = x;
  96. T yn = y;
  97. T zn = z;
  98. T An = (x + y + z) / 3;
  99. T A0 = An;
  100. T Q = pow(3 * boost::math::tools::epsilon<T>(), T(-1) / 8) * BOOST_MATH_GPU_SAFE_MAX(BOOST_MATH_GPU_SAFE_MAX(fabs(An - xn), fabs(An - yn)), fabs(An - zn));
  101. T fn = 1;
  102. // duplication
  103. unsigned k = 1;
  104. for(; k < boost::math::policies::get_max_series_iterations<Policy>(); ++k)
  105. {
  106. T root_x = sqrt(xn);
  107. T root_y = sqrt(yn);
  108. T root_z = sqrt(zn);
  109. T lambda = root_x * root_y + root_x * root_z + root_y * root_z;
  110. An = (An + lambda) / 4;
  111. xn = (xn + lambda) / 4;
  112. yn = (yn + lambda) / 4;
  113. zn = (zn + lambda) / 4;
  114. Q /= 4;
  115. fn *= 4;
  116. if(Q < fabs(An))
  117. break;
  118. }
  119. // Check to see if we gave up too soon:
  120. policies::check_series_iterations<T>(function, k, pol);
  121. BOOST_MATH_INSTRUMENT_VARIABLE(k);
  122. T X = (A0 - x) / (An * fn);
  123. T Y = (A0 - y) / (An * fn);
  124. T Z = -X - Y;
  125. // Taylor series expansion to the 7th order
  126. T E2 = X * Y - Z * Z;
  127. T E3 = X * Y * Z;
  128. return (1 + E3 * (T(1) / 14 + 3 * E3 / 104) + E2 * (T(-1) / 10 + E2 / 24 - (3 * E3) / 44 - 5 * E2 * E2 / 208 + E2 * E3 / 16)) / sqrt(An);
  129. }
  130. } // namespace detail
  131. template <class T1, class T2, class T3, class Policy>
  132. BOOST_MATH_GPU_ENABLED inline typename tools::promote_args<T1, T2, T3>::type
  133. ellint_rf(T1 x, T2 y, T3 z, const Policy& pol)
  134. {
  135. typedef typename tools::promote_args<T1, T2, T3>::type result_type;
  136. typedef typename policies::evaluation<result_type, Policy>::type value_type;
  137. return policies::checked_narrowing_cast<result_type, Policy>(
  138. detail::ellint_rf_imp(
  139. static_cast<value_type>(x),
  140. static_cast<value_type>(y),
  141. static_cast<value_type>(z), pol), "boost::math::ellint_rf<%1%>(%1%,%1%,%1%)");
  142. }
  143. template <class T1, class T2, class T3>
  144. BOOST_MATH_GPU_ENABLED inline typename tools::promote_args<T1, T2, T3>::type
  145. ellint_rf(T1 x, T2 y, T3 z)
  146. {
  147. return ellint_rf(x, y, z, policies::policy<>());
  148. }
  149. }} // namespaces
  150. #endif // BOOST_MATH_ELLINT_RF_HPP