File indexing completed on 2025-07-11 08:15:26
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef BOOST_MATH_ELLINT_3_HPP
0015 #define BOOST_MATH_ELLINT_3_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/special_functions/ellint_rf.hpp>
0023 #include <boost/math/special_functions/ellint_rj.hpp>
0024 #include <boost/math/special_functions/ellint_1.hpp>
0025 #include <boost/math/special_functions/ellint_2.hpp>
0026 #include <boost/math/special_functions/log1p.hpp>
0027 #include <boost/math/special_functions/atanh.hpp>
0028 #include <boost/math/constants/constants.hpp>
0029 #include <boost/math/policies/error_handling.hpp>
0030 #include <boost/math/tools/workaround.hpp>
0031 #include <boost/math/special_functions/round.hpp>
0032
0033
0034
0035
0036 namespace boost { namespace math {
0037
0038 namespace detail{
0039
0040 template <typename T, typename Policy>
0041 T ellint_pi_imp(T v, T k, T vc, const Policy& pol);
0042
0043
0044 template <typename T, typename Policy>
0045 T ellint_pi_imp(T v, T phi, T k, T vc, const Policy& pol)
0046 {
0047
0048 BOOST_MATH_STD_USING
0049
0050 static const char* function = "boost::math::ellint_3<%1%>(%1%,%1%,%1%)";
0051
0052
0053 T sphi = sin(fabs(phi));
0054 T result = 0;
0055
0056 if (k * k * sphi * sphi > 1)
0057 {
0058 return policies::raise_domain_error<T>(function, "Got k = %1%, function requires |k| <= 1", k, pol);
0059 }
0060
0061 if(v == 0)
0062 {
0063
0064 return (k == 0) ? phi : ellint_f_imp(phi, k, pol);
0065 }
0066 if((v > 0) && (1 / v < (sphi * sphi)))
0067 {
0068
0069 return policies::raise_domain_error<T>(function, "Got v = %1%, but result is complex for v > 1 / sin^2(phi)", v, pol);
0070 }
0071
0072 if(v == 1)
0073 {
0074 if (k == 0)
0075 return tan(phi);
0076
0077
0078 T m = k * k;
0079 result = sqrt(1 - m * sphi * sphi) * tan(phi) - ellint_e_imp(phi, k, pol);
0080 result /= 1 - m;
0081 result += ellint_f_imp(phi, k, pol);
0082 return result;
0083 }
0084 if(phi == constants::half_pi<T>())
0085 {
0086
0087
0088
0089
0090
0091
0092
0093 return ellint_pi_imp(v, k, vc, pol);
0094 }
0095 if((phi > constants::half_pi<T>()) || (phi < 0))
0096 {
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106 if(fabs(phi) > 1 / tools::epsilon<T>())
0107 {
0108
0109 BOOST_MATH_ASSERT(v <= 1);
0110
0111
0112
0113
0114 result = 2 * fabs(phi) * ellint_pi_imp(v, k, vc, pol) / constants::pi<T>();
0115 }
0116 else
0117 {
0118 T rphi = boost::math::tools::fmod_workaround(T(fabs(phi)), T(constants::half_pi<T>()));
0119 T m = boost::math::round((fabs(phi) - rphi) / constants::half_pi<T>());
0120 int sign = 1;
0121 if((m != 0) && (k >= 1))
0122 {
0123 return policies::raise_domain_error<T>(function, "Got k=1 and phi=%1% but the result is complex in that domain", phi, pol);
0124 }
0125 if(boost::math::tools::fmod_workaround(m, T(2)) > T(0.5))
0126 {
0127 m += 1;
0128 sign = -1;
0129 rphi = constants::half_pi<T>() - rphi;
0130 }
0131 result = sign * ellint_pi_imp(v, rphi, k, vc, pol);
0132 if((m > 0) && (vc > 0))
0133 result += m * ellint_pi_imp(v, k, vc, pol);
0134 }
0135 return phi < 0 ? T(-result) : result;
0136 }
0137 if(k == 0)
0138 {
0139
0140 if(v < 1)
0141 {
0142 T vcr = sqrt(vc);
0143 return atan(vcr * tan(phi)) / vcr;
0144 }
0145 else
0146 {
0147
0148 T vcr = sqrt(-vc);
0149 T arg = vcr * tan(phi);
0150 return (boost::math::log1p(arg, pol) - boost::math::log1p(-arg, pol)) / (2 * vcr);
0151 }
0152 }
0153 if((v < 0) && fabs(k) <= 1)
0154 {
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174 T k2 = k * k;
0175 T N = (k2 - v) / (1 - v);
0176 T Nm1 = (1 - k2) / (1 - v);
0177 T p2 = -v * N;
0178 T t;
0179 if (p2 <= tools::min_value<T>())
0180 {
0181 p2 = sqrt(-v) * sqrt(N);
0182 }
0183 else
0184 p2 = sqrt(p2);
0185 T delta = sqrt(1 - k2 * sphi * sphi);
0186 if(N > k2)
0187 {
0188 result = ellint_pi_imp(N, phi, k, Nm1, pol);
0189 result *= v / (v - 1);
0190 result *= (k2 - 1) / (v - k2);
0191 }
0192
0193 if(k != 0)
0194 {
0195 t = ellint_f_imp(phi, k, pol);
0196 t *= k2 / (k2 - v);
0197 result += t;
0198 }
0199 t = v / ((k2 - v) * (v - 1));
0200 if(t > tools::min_value<T>())
0201 {
0202 result += atan((p2 / 2) * sin(2 * phi) / delta) * sqrt(t);
0203 }
0204 else
0205 {
0206 result += atan((p2 / 2) * sin(2 * phi) / delta) * sqrt(fabs(1 / (k2 - v))) * sqrt(fabs(v / (v - 1)));
0207 }
0208 return result;
0209 }
0210 if(k == 1)
0211 {
0212
0213 result = sqrt(v) * atanh(sqrt(v) * sin(phi), pol) - log(1 / cos(phi) + tan(phi));
0214 result /= v - 1;
0215 return result;
0216 }
0217 #if 0
0218 if(v > 1)
0219 {
0220
0221
0222
0223
0224
0225
0226
0227 T k2 = k * k;
0228 T N = k2 / v;
0229 T Nm1 = (v - k2) / v;
0230 T p1 = sqrt((-vc) * (1 - k2 / v));
0231 T delta = sqrt(1 - k2 * sphi * sphi);
0232
0233
0234
0235
0236
0237 result = -ellint_pi_imp(N, phi, k, Nm1, pol);
0238 result += ellint_f_imp(phi, k, pol);
0239
0240
0241
0242
0243
0244
0245 result += log((delta + p1 * tan(phi)) / (delta - p1 * tan(phi))) / (2 * p1);
0246 return result;
0247 }
0248 #endif
0249
0250
0251
0252
0253
0254 BOOST_MATH_ASSERT(fabs(phi) < constants::half_pi<T>());
0255 BOOST_MATH_ASSERT(phi >= 0);
0256 T x, y, z, p, t;
0257 T cosp = cos(phi);
0258 x = cosp * cosp;
0259 t = sphi * sphi;
0260 y = 1 - k * k * t;
0261 z = 1;
0262 if(v * t < T(0.5))
0263 p = 1 - v * t;
0264 else
0265 p = x + vc * t;
0266 result = sphi * (ellint_rf_imp(x, y, z, pol) + v * t * ellint_rj_imp(x, y, z, p, pol) / 3);
0267
0268 return result;
0269 }
0270
0271
0272 template <typename T, typename Policy>
0273 T ellint_pi_imp(T v, T k, T vc, const Policy& pol)
0274 {
0275
0276 BOOST_MATH_STD_USING
0277 using namespace boost::math::tools;
0278
0279 static const char* function = "boost::math::ellint_pi<%1%>(%1%,%1%)";
0280
0281 if (abs(k) >= 1)
0282 {
0283 return policies::raise_domain_error<T>(function, "Got k = %1%, function requires |k| <= 1", k, pol);
0284 }
0285 if(vc <= 0)
0286 {
0287
0288 return policies::raise_domain_error<T>(function, "Got v = %1%, function requires v < 1", v, pol);
0289 }
0290
0291 if(v == 0)
0292 {
0293 return (k == 0) ? boost::math::constants::pi<T>() / 2 : boost::math::ellint_1(k, pol);
0294 }
0295
0296 if(v < 0)
0297 {
0298
0299 T k2 = k * k;
0300 T N = (k2 - v) / (1 - v);
0301 T Nm1 = (1 - k2) / (1 - v);
0302 T result = 0;
0303 result = boost::math::detail::ellint_pi_imp(N, k, Nm1, pol);
0304
0305 result *= -v / (1 - v);
0306 result *= (1 - k2) / (k2 - v);
0307 result += boost::math::ellint_1(k, pol) * k2 / (k2 - v);
0308 return result;
0309 }
0310
0311 T x = 0;
0312 T y = 1 - k * k;
0313 T z = 1;
0314 T p = vc;
0315 T value = ellint_rf_imp(x, y, z, pol) + v * ellint_rj_imp(x, y, z, p, pol) / 3;
0316
0317 return value;
0318 }
0319
0320 template <class T1, class T2, class T3>
0321 inline typename tools::promote_args<T1, T2, T3>::type ellint_3(T1 k, T2 v, T3 phi, const std::false_type&)
0322 {
0323 return boost::math::ellint_3(k, v, phi, policies::policy<>());
0324 }
0325
0326 template <class T1, class T2, class Policy>
0327 inline typename tools::promote_args<T1, T2>::type ellint_3(T1 k, T2 v, const Policy& pol, const std::true_type&)
0328 {
0329 typedef typename tools::promote_args<T1, T2>::type result_type;
0330 typedef typename policies::evaluation<result_type, Policy>::type value_type;
0331 return policies::checked_narrowing_cast<result_type, Policy>(
0332 detail::ellint_pi_imp(
0333 static_cast<value_type>(v),
0334 static_cast<value_type>(k),
0335 static_cast<value_type>(1-v),
0336 pol), "boost::math::ellint_3<%1%>(%1%,%1%)");
0337 }
0338
0339 }
0340
0341 template <class T1, class T2, class T3, class Policy>
0342 inline typename tools::promote_args<T1, T2, T3>::type ellint_3(T1 k, T2 v, T3 phi, const Policy&)
0343 {
0344 typedef typename tools::promote_args<T1, T2, T3>::type result_type;
0345 typedef typename policies::evaluation<result_type, Policy>::type value_type;
0346 typedef typename policies::normalise<Policy, policies::promote_float<false>, policies::promote_double<false> >::type forwarding_policy;
0347 return policies::checked_narrowing_cast<result_type, Policy>(
0348 detail::ellint_pi_imp(
0349 static_cast<value_type>(v),
0350 static_cast<value_type>(phi),
0351 static_cast<value_type>(k),
0352 static_cast<value_type>(1-v),
0353 forwarding_policy()), "boost::math::ellint_3<%1%>(%1%,%1%,%1%)");
0354 }
0355
0356 template <class T1, class T2, class T3>
0357 typename detail::ellint_3_result<T1, T2, T3>::type ellint_3(T1 k, T2 v, T3 phi)
0358 {
0359 typedef typename policies::is_policy<T3>::type tag_type;
0360 return detail::ellint_3(k, v, phi, tag_type());
0361 }
0362
0363 template <class T1, class T2>
0364 inline typename tools::promote_args<T1, T2>::type ellint_3(T1 k, T2 v)
0365 {
0366 return ellint_3(k, v, policies::policy<>());
0367 }
0368
0369 }}
0370
0371 #endif
0372