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