File indexing completed on 2025-07-15 08:38:17
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef BOOST_MATH_ELLINT_RJ_HPP
0015 #define BOOST_MATH_ELLINT_RJ_HPP
0016
0017 #ifdef _MSC_VER
0018 #pragma once
0019 #endif
0020
0021 #include <boost/math/special_functions/math_fwd.hpp>
0022 #include <boost/math/tools/config.hpp>
0023 #include <boost/math/policies/error_handling.hpp>
0024 #include <boost/math/special_functions/ellint_rc.hpp>
0025 #include <boost/math/special_functions/ellint_rf.hpp>
0026 #include <boost/math/special_functions/ellint_rd.hpp>
0027
0028
0029
0030
0031
0032 namespace boost { namespace math { namespace detail{
0033
0034 template <typename T, typename Policy>
0035 T ellint_rc1p_imp(T y, const Policy& pol)
0036 {
0037 using namespace boost::math;
0038
0039 BOOST_MATH_STD_USING
0040
0041 BOOST_MATH_ASSERT(y != -1);
0042
0043
0044 T result;
0045 if(y < -1)
0046 {
0047 result = sqrt(1 / -y) * detail::ellint_rc_imp(T(-y), T(-1 - y), pol);
0048 }
0049 else if(y == 0)
0050 {
0051 result = 1;
0052 }
0053 else if(y > 0)
0054 {
0055 result = atan(sqrt(y)) / sqrt(y);
0056 }
0057 else
0058 {
0059 if(y > T(-0.5))
0060 {
0061 T arg = sqrt(-y);
0062 result = (boost::math::log1p(arg, pol) - boost::math::log1p(-arg, pol)) / (2 * sqrt(-y));
0063 }
0064 else
0065 {
0066 result = log((1 + sqrt(-y)) / sqrt(1 + y)) / sqrt(-y);
0067 }
0068 }
0069 return result;
0070 }
0071
0072 template <typename T, typename Policy>
0073 T ellint_rj_imp(T x, T y, T z, T p, const Policy& pol)
0074 {
0075 BOOST_MATH_STD_USING
0076
0077 static const char* function = "boost::math::ellint_rj<%1%>(%1%,%1%,%1%)";
0078
0079 if(x < 0)
0080 {
0081 return policies::raise_domain_error<T>(function, "Argument x must be non-negative, but got x = %1%", x, pol);
0082 }
0083 if(y < 0)
0084 {
0085 return policies::raise_domain_error<T>(function, "Argument y must be non-negative, but got y = %1%", y, pol);
0086 }
0087 if(z < 0)
0088 {
0089 return policies::raise_domain_error<T>(function, "Argument z must be non-negative, but got z = %1%", z, pol);
0090 }
0091 if(p == 0)
0092 {
0093 return policies::raise_domain_error<T>(function, "Argument p must not be zero, but got p = %1%", p, pol);
0094 }
0095 if(x + y == 0 || y + z == 0 || z + x == 0)
0096 {
0097 return policies::raise_domain_error<T>(function, "At most one argument can be zero, only possible result is %1%.", std::numeric_limits<T>::quiet_NaN(), pol);
0098 }
0099
0100
0101 if(p < 0)
0102 {
0103
0104
0105
0106
0107
0108 if(x > y)
0109 std::swap(x, y);
0110 if(y > z)
0111 std::swap(y, z);
0112 if(x > y)
0113 std::swap(x, y);
0114
0115 BOOST_MATH_ASSERT(x <= y);
0116 BOOST_MATH_ASSERT(y <= z);
0117
0118 T q = -p;
0119 p = (z * (x + y + q) - x * y) / (z + q);
0120
0121 BOOST_MATH_ASSERT(p >= 0);
0122
0123 T value = (p - z) * ellint_rj_imp(x, y, z, p, pol);
0124 value -= 3 * ellint_rf_imp(x, y, z, pol);
0125 value += 3 * sqrt((x * y * z) / (x * y + p * q)) * ellint_rc_imp(T(x * y + p * q), T(p * q), pol);
0126 value /= (z + q);
0127 return value;
0128 }
0129
0130
0131
0132
0133 if(x == y)
0134 {
0135 if(x == z)
0136 {
0137 if(x == p)
0138 {
0139
0140 return 1 / (x * sqrt(x));
0141 }
0142 else
0143 {
0144
0145 return 3 * (ellint_rc_imp(x, p, pol) - 1 / sqrt(x)) / (x - p);
0146 }
0147 }
0148 else
0149 {
0150
0151 using std::swap;
0152 swap(x, z);
0153 if(y == p)
0154 {
0155 return ellint_rd_imp(x, y, y, pol);
0156 }
0157 else if((std::max)(y, p) / (std::min)(y, p) > T(1.2))
0158 {
0159 return 3 * (ellint_rc_imp(x, y, pol) - ellint_rc_imp(x, p, pol)) / (p - y);
0160 }
0161
0162 }
0163 }
0164 if(y == z)
0165 {
0166 if(y == p)
0167 {
0168
0169 return ellint_rd_imp(x, y, y, pol);
0170 }
0171 else if((std::max)(y, p) / (std::min)(y, p) > T(1.2))
0172 {
0173
0174 return 3 * (ellint_rc_imp(x, y, pol) - ellint_rc_imp(x, p, pol)) / (p - y);
0175 }
0176
0177 }
0178 if(z == p)
0179 {
0180 return ellint_rd_imp(x, y, z, pol);
0181 }
0182
0183 T xn = x;
0184 T yn = y;
0185 T zn = z;
0186 T pn = p;
0187 T An = (x + y + z + 2 * p) / 5;
0188 T A0 = An;
0189 T delta = (p - x) * (p - y) * (p - z);
0190 T Q = pow(tools::epsilon<T>() / 5, -T(1) / 8) * (std::max)((std::max)(fabs(An - x), fabs(An - y)), (std::max)(fabs(An - z), fabs(An - p)));
0191
0192 unsigned n;
0193 T lambda;
0194 T Dn;
0195 T En;
0196 T rx, ry, rz, rp;
0197 T fmn = 1;
0198 T RC_sum = 0;
0199
0200 for(n = 0; n < policies::get_max_series_iterations<Policy>(); ++n)
0201 {
0202 rx = sqrt(xn);
0203 ry = sqrt(yn);
0204 rz = sqrt(zn);
0205 rp = sqrt(pn);
0206 Dn = (rp + rx) * (rp + ry) * (rp + rz);
0207 En = delta / Dn;
0208 En /= Dn;
0209 if((En < T(-0.5)) && (En > T(-1.5)))
0210 {
0211
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223
0224 T b = 2 * rp * (pn + rx * (ry + rz) + ry * rz) / Dn;
0225 RC_sum += fmn / Dn * detail::ellint_rc_imp(T(1), b, pol);
0226 }
0227 else
0228 {
0229 RC_sum += fmn / Dn * ellint_rc1p_imp(En, pol);
0230 }
0231 lambda = rx * ry + rx * rz + ry * rz;
0232
0233
0234 An = (An + lambda) / 4;
0235 fmn /= 4;
0236
0237 if(fmn * Q < An)
0238 break;
0239
0240 xn = (xn + lambda) / 4;
0241 yn = (yn + lambda) / 4;
0242 zn = (zn + lambda) / 4;
0243 pn = (pn + lambda) / 4;
0244 delta /= 64;
0245 }
0246
0247 T X = fmn * (A0 - x) / An;
0248 T Y = fmn * (A0 - y) / An;
0249 T Z = fmn * (A0 - z) / An;
0250 T P = (-X - Y - Z) / 2;
0251 T E2 = X * Y + X * Z + Y * Z - 3 * P * P;
0252 T E3 = X * Y * Z + 2 * E2 * P + 4 * P * P * P;
0253 T E4 = (2 * X * Y * Z + E2 * P + 3 * P * P * P) * P;
0254 T E5 = X * Y * Z * P * P;
0255 T result = fmn * pow(An, T(-3) / 2) *
0256 (1 - 3 * E2 / 14 + E3 / 6 + 9 * E2 * E2 / 88 - 3 * E4 / 22 - 9 * E2 * E3 / 52 + 3 * E5 / 26 - E2 * E2 * E2 / 16
0257 + 3 * E3 * E3 / 40 + 3 * E2 * E4 / 20 + 45 * E2 * E2 * E3 / 272 - 9 * (E3 * E4 + E2 * E5) / 68);
0258
0259 result += 6 * RC_sum;
0260 return result;
0261 }
0262
0263 }
0264
0265 template <class T1, class T2, class T3, class T4, class Policy>
0266 inline typename tools::promote_args<T1, T2, T3, T4>::type
0267 ellint_rj(T1 x, T2 y, T3 z, T4 p, const Policy& pol)
0268 {
0269 typedef typename tools::promote_args<T1, T2, T3, T4>::type result_type;
0270 typedef typename policies::evaluation<result_type, Policy>::type value_type;
0271 return policies::checked_narrowing_cast<result_type, Policy>(
0272 detail::ellint_rj_imp(
0273 static_cast<value_type>(x),
0274 static_cast<value_type>(y),
0275 static_cast<value_type>(z),
0276 static_cast<value_type>(p),
0277 pol), "boost::math::ellint_rj<%1%>(%1%,%1%,%1%,%1%)");
0278 }
0279
0280 template <class T1, class T2, class T3, class T4>
0281 inline typename tools::promote_args<T1, T2, T3, T4>::type
0282 ellint_rj(T1 x, T2 y, T3 z, T4 p)
0283 {
0284 return ellint_rj(x, y, z, p, policies::policy<>());
0285 }
0286
0287 }}
0288
0289 #endif
0290