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