Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-10-20 08:29:23

0001 //  Copyright (c) 2006 Xiaogang Zhang
0002 //  Copyright (c) 2006 John Maddock
0003 //  Copyright (c) 2024 Matt Borland
0004 //  Use, modification and distribution are subject to the
0005 //  Boost Software License, Version 1.0. (See accompanying file
0006 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0007 //
0008 //  History:
0009 //  XZ wrote the original of this file as part of the Google
0010 //  Summer of Code 2006.  JM modified it to fit into the
0011 //  Boost.Math conceptual framework better, and to ensure
0012 //  that the code continues to work no matter how many digits
0013 //  type T has.
0014 
0015 #ifndef BOOST_MATH_ELLINT_D_HPP
0016 #define BOOST_MATH_ELLINT_D_HPP
0017 
0018 #ifdef _MSC_VER
0019 #pragma once
0020 #endif
0021 
0022 #include <boost/math/tools/config.hpp>
0023 #include <boost/math/tools/type_traits.hpp>
0024 #include <boost/math/special_functions/math_fwd.hpp>
0025 #include <boost/math/special_functions/ellint_rf.hpp>
0026 #include <boost/math/special_functions/ellint_rd.hpp>
0027 #include <boost/math/special_functions/ellint_rg.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 // Elliptic integrals (complete and incomplete) of the second kind
0034 // Carlson, Numerische Mathematik, vol 33, 1 (1979)
0035 
0036 namespace boost { namespace math {
0037 
0038 template <class T1, class T2, class Policy>
0039 BOOST_MATH_GPU_ENABLED typename tools::promote_args<T1, T2>::type ellint_d(T1 k, T2 phi, const Policy& pol);
0040 
0041 namespace detail{
0042 
0043 template <typename T, typename Policy>
0044 BOOST_MATH_GPU_ENABLED T ellint_d_imp(T k, const Policy& pol);
0045 
0046 // Elliptic integral (Legendre form) of the second kind
0047 template <typename T, typename Policy>
0048 BOOST_MATH_GPU_ENABLED T ellint_d_imp(T phi, T k, const Policy& pol)
0049 {
0050     BOOST_MATH_STD_USING
0051     using namespace boost::math::tools;
0052     using namespace boost::math::constants;
0053 
0054     bool invert = false;
0055     if(phi < 0)
0056     {
0057        phi = fabs(phi);
0058        invert = true;
0059     }
0060 
0061     T result;
0062 
0063     if(phi >= tools::max_value<T>())
0064     {
0065        // Need to handle infinity as a special case:
0066        result = policies::raise_overflow_error<T>("boost::math::ellint_d<%1%>(%1%,%1%)", nullptr, pol);
0067     }
0068     else if(phi > 1 / tools::epsilon<T>())
0069     {
0070        // Phi is so large that phi%pi is necessarily zero (or garbage),
0071        // just return the second part of the duplication formula:
0072        result = 2 * phi * ellint_d_imp(k, pol) / constants::pi<T>();
0073     }
0074     else
0075     {
0076        // Carlson's algorithm works only for |phi| <= pi/2,
0077        // use the integrand's periodicity to normalize phi
0078        //
0079        T rphi = boost::math::tools::fmod_workaround(phi, T(constants::half_pi<T>()));
0080        T m = boost::math::round((phi - rphi) / constants::half_pi<T>());
0081        int s = 1;
0082        if(boost::math::tools::fmod_workaround(m, T(2)) > T(0.5))
0083        {
0084           m += 1;
0085           s = -1;
0086           rphi = constants::half_pi<T>() - rphi;
0087        }
0088        BOOST_MATH_INSTRUMENT_VARIABLE(rphi);
0089        BOOST_MATH_INSTRUMENT_VARIABLE(m);
0090        T sinp = sin(rphi);
0091        T cosp = cos(rphi);
0092        BOOST_MATH_INSTRUMENT_VARIABLE(sinp);
0093        BOOST_MATH_INSTRUMENT_VARIABLE(cosp);
0094        T c = 1 / (sinp * sinp);
0095        T cm1 = cosp * cosp / (sinp * sinp);  // c - 1
0096        T k2 = k * k;
0097        if(k2 * sinp * sinp > 1)
0098        {
0099           return policies::raise_domain_error<T>("boost::math::ellint_d<%1%>(%1%, %1%)", "The parameter k is out of range, got k = %1%", k, pol);
0100        }
0101        else if(rphi == 0)
0102        {
0103           result = 0;
0104        }
0105        else
0106        {
0107           // http://dlmf.nist.gov/19.25#E10
0108           result = s * ellint_rd_imp(cm1, T(c - k2), c, pol) / 3;
0109           BOOST_MATH_INSTRUMENT_VARIABLE(result);
0110        }
0111        if(m != 0)
0112           result += m * ellint_d_imp(k, pol);
0113     }
0114     return invert ? T(-result) : result;
0115 }
0116 
0117 // Complete elliptic integral (Legendre form) of the second kind
0118 template <typename T, typename Policy>
0119 BOOST_MATH_GPU_ENABLED T ellint_d_imp(T k, const Policy& pol)
0120 {
0121     BOOST_MATH_STD_USING
0122     using namespace boost::math::tools;
0123 
0124     if (abs(k) >= 1)
0125     {
0126        return policies::raise_domain_error<T>("boost::math::ellint_d<%1%>(%1%)", "Got k = %1%, function requires |k| <= 1", k, pol);
0127     }
0128     if(fabs(k) <= tools::root_epsilon<T>())
0129        return constants::pi<T>() / 4;
0130 
0131     T x = 0;
0132     T t = k * k;
0133     T y = 1 - t;
0134     T z = 1;
0135     T value = ellint_rd_imp(x, y, z, pol) / 3;
0136 
0137     return value;
0138 }
0139 
0140 template <typename T, typename Policy>
0141 BOOST_MATH_GPU_ENABLED inline typename tools::promote_args<T>::type ellint_d(T k, const Policy& pol, const boost::math::true_type&)
0142 {
0143    typedef typename tools::promote_args<T>::type result_type;
0144    typedef typename policies::evaluation<result_type, Policy>::type value_type;
0145    return policies::checked_narrowing_cast<result_type, Policy>(detail::ellint_d_imp(static_cast<value_type>(k), pol), "boost::math::ellint_d<%1%>(%1%)");
0146 }
0147 
0148 // Elliptic integral (Legendre form) of the second kind
0149 template <class T1, class T2>
0150 BOOST_MATH_GPU_ENABLED inline typename tools::promote_args<T1, T2>::type ellint_d(T1 k, T2 phi, const boost::math::false_type&)
0151 {
0152    return boost::math::ellint_d(k, phi, policies::policy<>());
0153 }
0154 
0155 } // detail
0156 
0157 // Complete elliptic integral (Legendre form) of the second kind
0158 template <typename T>
0159 BOOST_MATH_GPU_ENABLED inline typename tools::promote_args<T>::type ellint_d(T k)
0160 {
0161    return ellint_d(k, policies::policy<>());
0162 }
0163 
0164 // Elliptic integral (Legendre form) of the second kind
0165 template <class T1, class T2>
0166 BOOST_MATH_GPU_ENABLED inline typename tools::promote_args<T1, T2>::type ellint_d(T1 k, T2 phi)
0167 {
0168    typedef typename policies::is_policy<T2>::type tag_type;
0169    return detail::ellint_d(k, phi, tag_type());
0170 }
0171 
0172 template <class T1, class T2, class Policy>
0173 BOOST_MATH_GPU_ENABLED inline typename tools::promote_args<T1, T2>::type ellint_d(T1 k, T2 phi, const Policy& pol)
0174 {
0175    typedef typename tools::promote_args<T1, T2>::type result_type;
0176    typedef typename policies::evaluation<result_type, Policy>::type value_type;
0177    return policies::checked_narrowing_cast<result_type, Policy>(detail::ellint_d_imp(static_cast<value_type>(phi), static_cast<value_type>(k), pol), "boost::math::ellint_2<%1%>(%1%,%1%)");
0178 }
0179 
0180 }} // namespaces
0181 
0182 #endif // BOOST_MATH_ELLINT_D_HPP
0183