377 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
		
		
			
		
	
	
			377 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| 
								 | 
							
								//  Copyright (c) 2006 Xiaogang Zhang
							 | 
						||
| 
								 | 
							
								//  Copyright (c) 2006 John Maddock
							 | 
						||
| 
								 | 
							
								//  Use, modification and distribution are subject to the
							 | 
						||
| 
								 | 
							
								//  Boost Software License, Version 1.0. (See accompanying file
							 | 
						||
| 
								 | 
							
								//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//  History:
							 | 
						||
| 
								 | 
							
								//  XZ wrote the original of this file as part of the Google
							 | 
						||
| 
								 | 
							
								//  Summer of Code 2006.  JM modified it to fit into the
							 | 
						||
| 
								 | 
							
								//  Boost.Math conceptual framework better, and to correctly
							 | 
						||
| 
								 | 
							
								//  handle the various corner cases.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifndef BOOST_MATH_ELLINT_3_HPP
							 | 
						||
| 
								 | 
							
								#define BOOST_MATH_ELLINT_3_HPP
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifdef _MSC_VER
							 | 
						||
| 
								 | 
							
								#pragma once
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <boost/math/special_functions/math_fwd.hpp>
							 | 
						||
| 
								 | 
							
								#include <boost/math/special_functions/ellint_rf.hpp>
							 | 
						||
| 
								 | 
							
								#include <boost/math/special_functions/ellint_rj.hpp>
							 | 
						||
| 
								 | 
							
								#include <boost/math/special_functions/ellint_1.hpp>
							 | 
						||
| 
								 | 
							
								#include <boost/math/special_functions/ellint_2.hpp>
							 | 
						||
| 
								 | 
							
								#include <boost/math/special_functions/log1p.hpp>
							 | 
						||
| 
								 | 
							
								#include <boost/math/special_functions/atanh.hpp>
							 | 
						||
| 
								 | 
							
								#include <boost/math/constants/constants.hpp>
							 | 
						||
| 
								 | 
							
								#include <boost/math/policies/error_handling.hpp>
							 | 
						||
| 
								 | 
							
								#include <boost/math/tools/workaround.hpp>
							 | 
						||
| 
								 | 
							
								#include <boost/math/special_functions/round.hpp>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Elliptic integrals (complete and incomplete) of the third kind
							 | 
						||
| 
								 | 
							
								// Carlson, Numerische Mathematik, vol 33, 1 (1979)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								namespace boost { namespace math { 
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								namespace detail{
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								template <typename T, typename Policy>
							 | 
						||
| 
								 | 
							
								T ellint_pi_imp(T v, T k, T vc, const Policy& pol);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Elliptic integral (Legendre form) of the third kind
							 | 
						||
| 
								 | 
							
								template <typename T, typename Policy>
							 | 
						||
| 
								 | 
							
								T ellint_pi_imp(T v, T phi, T k, T vc, const Policy& pol)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								   // Note vc = 1-v presumably without cancellation error.
							 | 
						||
| 
								 | 
							
								   BOOST_MATH_STD_USING
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   static const char* function = "boost::math::ellint_3<%1%>(%1%,%1%,%1%)";
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   if(abs(k) > 1)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      return policies::raise_domain_error<T>(function,
							 | 
						||
| 
								 | 
							
								         "Got k = %1%, function requires |k| <= 1", k, pol);
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   T sphi = sin(fabs(phi));
							 | 
						||
| 
								 | 
							
								   T result = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   // Special cases first:
							 | 
						||
| 
								 | 
							
								   if(v == 0)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      // A&S 17.7.18 & 19
							 | 
						||
| 
								 | 
							
								      return (k == 0) ? phi : ellint_f_imp(phi, k, pol);
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   if((v > 0) && (1 / v < (sphi * sphi)))
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      // Complex result is a domain error:
							 | 
						||
| 
								 | 
							
								      return policies::raise_domain_error<T>(function,
							 | 
						||
| 
								 | 
							
								         "Got v = %1%, but result is complex for v > 1 / sin^2(phi)", v, pol);
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   if(v == 1)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      // http://functions.wolfram.com/08.06.03.0008.01
							 | 
						||
| 
								 | 
							
								      T m = k * k;
							 | 
						||
| 
								 | 
							
								      result = sqrt(1 - m * sphi * sphi) * tan(phi) - ellint_e_imp(phi, k, pol);
							 | 
						||
| 
								 | 
							
								      result /= 1 - m;
							 | 
						||
| 
								 | 
							
								      result += ellint_f_imp(phi, k, pol);
							 | 
						||
| 
								 | 
							
								      return result;
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   if(phi == constants::half_pi<T>())
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      // Have to filter this case out before the next
							 | 
						||
| 
								 | 
							
								      // special case, otherwise we might get an infinity from
							 | 
						||
| 
								 | 
							
								      // tan(phi).
							 | 
						||
| 
								 | 
							
								      // Also note that since we can't represent PI/2 exactly
							 | 
						||
| 
								 | 
							
								      // in a T, this is a bit of a guess as to the users true
							 | 
						||
| 
								 | 
							
								      // intent...
							 | 
						||
| 
								 | 
							
								      //
							 | 
						||
| 
								 | 
							
								      return ellint_pi_imp(v, k, vc, pol);
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   if((phi > constants::half_pi<T>()) || (phi < 0))
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      // Carlson's algorithm works only for |phi| <= pi/2,
							 | 
						||
| 
								 | 
							
								      // use the integrand's periodicity to normalize phi
							 | 
						||
| 
								 | 
							
								      //
							 | 
						||
| 
								 | 
							
								      // Xiaogang's original code used a cast to long long here
							 | 
						||
| 
								 | 
							
								      // but that fails if T has more digits than a long long,
							 | 
						||
| 
								 | 
							
								      // so rewritten to use fmod instead:
							 | 
						||
| 
								 | 
							
								      //
							 | 
						||
| 
								 | 
							
								      // See http://functions.wolfram.com/08.06.16.0002.01
							 | 
						||
| 
								 | 
							
								      //
							 | 
						||
| 
								 | 
							
								      if(fabs(phi) > 1 / tools::epsilon<T>())
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								         if(v > 1)
							 | 
						||
| 
								 | 
							
								            return policies::raise_domain_error<T>(
							 | 
						||
| 
								 | 
							
								            function,
							 | 
						||
| 
								 | 
							
								            "Got v = %1%, but this is only supported for 0 <= phi <= pi/2", v, pol);
							 | 
						||
| 
								 | 
							
								         //  
							 | 
						||
| 
								 | 
							
								         // Phi is so large that phi%pi is necessarily zero (or garbage),
							 | 
						||
| 
								 | 
							
								         // just return the second part of the duplication formula:
							 | 
						||
| 
								 | 
							
								         //
							 | 
						||
| 
								 | 
							
								         result = 2 * fabs(phi) * ellint_pi_imp(v, k, vc, pol) / constants::pi<T>();
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      else
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								         T rphi = boost::math::tools::fmod_workaround(T(fabs(phi)), T(constants::half_pi<T>()));
							 | 
						||
| 
								 | 
							
								         T m = boost::math::round((fabs(phi) - rphi) / constants::half_pi<T>());
							 | 
						||
| 
								 | 
							
								         int sign = 1;
							 | 
						||
| 
								 | 
							
								         if((m != 0) && (k >= 1))
							 | 
						||
| 
								 | 
							
								         {
							 | 
						||
| 
								 | 
							
								            return policies::raise_domain_error<T>(function, "Got k=1 and phi=%1% but the result is complex in that domain", phi, pol);
							 | 
						||
| 
								 | 
							
								         }
							 | 
						||
| 
								 | 
							
								         if(boost::math::tools::fmod_workaround(m, T(2)) > 0.5)
							 | 
						||
| 
								 | 
							
								         {
							 | 
						||
| 
								 | 
							
								            m += 1;
							 | 
						||
| 
								 | 
							
								            sign = -1;
							 | 
						||
| 
								 | 
							
								            rphi = constants::half_pi<T>() - rphi;
							 | 
						||
| 
								 | 
							
								         }
							 | 
						||
| 
								 | 
							
								         result = sign * ellint_pi_imp(v, rphi, k, vc, pol);
							 | 
						||
| 
								 | 
							
								         if((m > 0) && (vc > 0))
							 | 
						||
| 
								 | 
							
								            result += m * ellint_pi_imp(v, k, vc, pol);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      return phi < 0 ? T(-result) : result;
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   if(k == 0)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      // A&S 17.7.20:
							 | 
						||
| 
								 | 
							
								      if(v < 1)
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								         T vcr = sqrt(vc);
							 | 
						||
| 
								 | 
							
								         return atan(vcr * tan(phi)) / vcr;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      else if(v == 1)
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								         return tan(phi);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      else
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								         // v > 1:
							 | 
						||
| 
								 | 
							
								         T vcr = sqrt(-vc);
							 | 
						||
| 
								 | 
							
								         T arg = vcr * tan(phi);
							 | 
						||
| 
								 | 
							
								         return (boost::math::log1p(arg, pol) - boost::math::log1p(-arg, pol)) / (2 * vcr);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   if(v < 0)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      //
							 | 
						||
| 
								 | 
							
								      // If we don't shift to 0 <= v <= 1 we get
							 | 
						||
| 
								 | 
							
								      // cancellation errors later on.  Use
							 | 
						||
| 
								 | 
							
								      // A&S 17.7.15/16 to shift to v > 0.
							 | 
						||
| 
								 | 
							
								      //
							 | 
						||
| 
								 | 
							
								      // Mathematica simplifies the expressions
							 | 
						||
| 
								 | 
							
								      // given in A&S as follows (with thanks to
							 | 
						||
| 
								 | 
							
								      // Rocco Romeo for figuring these out!):
							 | 
						||
| 
								 | 
							
								      //
							 | 
						||
| 
								 | 
							
								      // V = (k2 - n)/(1 - n)
							 | 
						||
| 
								 | 
							
								      // Assuming[(k2 >= 0 && k2 <= 1) && n < 0, FullSimplify[Sqrt[(1 - V)*(1 - k2 / V)] / Sqrt[((1 - n)*(1 - k2 / n))]]]
							 | 
						||
| 
								 | 
							
								      // Result: ((-1 + k2) n) / ((-1 + n) (-k2 + n))
							 | 
						||
| 
								 | 
							
								      //
							 | 
						||
| 
								 | 
							
								      // Assuming[(k2 >= 0 && k2 <= 1) && n < 0, FullSimplify[k2 / (Sqrt[-n*(k2 - n) / (1 - n)] * Sqrt[(1 - n)*(1 - k2 / n)])]]
							 | 
						||
| 
								 | 
							
								      // Result : k2 / (k2 - n)
							 | 
						||
| 
								 | 
							
								      //
							 | 
						||
| 
								 | 
							
								      // Assuming[(k2 >= 0 && k2 <= 1) && n < 0, FullSimplify[Sqrt[1 / ((1 - n)*(1 - k2 / n))]]]
							 | 
						||
| 
								 | 
							
								      // Result : Sqrt[n / ((k2 - n) (-1 + n))]
							 | 
						||
| 
								 | 
							
								      //
							 | 
						||
| 
								 | 
							
								      T k2 = k * k;
							 | 
						||
| 
								 | 
							
								      T N = (k2 - v) / (1 - v);
							 | 
						||
| 
								 | 
							
								      T Nm1 = (1 - k2) / (1 - v);
							 | 
						||
| 
								 | 
							
								      T p2 = -v * N;
							 | 
						||
| 
								 | 
							
								      T t;
							 | 
						||
| 
								 | 
							
								      if(p2 <= tools::min_value<T>())
							 | 
						||
| 
								 | 
							
								         p2 = sqrt(-v) * sqrt(N);
							 | 
						||
| 
								 | 
							
								      else
							 | 
						||
| 
								 | 
							
								         p2 = sqrt(p2);
							 | 
						||
| 
								 | 
							
								      T delta = sqrt(1 - k2 * sphi * sphi);
							 | 
						||
| 
								 | 
							
								      if(N > k2)
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								         result = ellint_pi_imp(N, phi, k, Nm1, pol);
							 | 
						||
| 
								 | 
							
								         result *= v / (v - 1);
							 | 
						||
| 
								 | 
							
								         result *= (k2 - 1) / (v - k2);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if(k != 0)
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								         t = ellint_f_imp(phi, k, pol);
							 | 
						||
| 
								 | 
							
								         t *= k2 / (k2 - v);
							 | 
						||
| 
								 | 
							
								         result += t;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      t = v / ((k2 - v) * (v - 1));
							 | 
						||
| 
								 | 
							
								      if(t > tools::min_value<T>())
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								         result += atan((p2 / 2) * sin(2 * phi) / delta) * sqrt(t);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      else
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								         result += atan((p2 / 2) * sin(2 * phi) / delta) * sqrt(fabs(1 / (k2 - v))) * sqrt(fabs(v / (v - 1)));
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      return result;
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   if(k == 1)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      // See http://functions.wolfram.com/08.06.03.0013.01
							 | 
						||
| 
								 | 
							
								      result = sqrt(v) * atanh(sqrt(v) * sin(phi)) - log(1 / cos(phi) + tan(phi));
							 | 
						||
| 
								 | 
							
								      result /= v - 1;
							 | 
						||
| 
								 | 
							
								      return result;
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								#if 0  // disabled but retained for future reference: see below.
							 | 
						||
| 
								 | 
							
								   if(v > 1)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      //
							 | 
						||
| 
								 | 
							
								      // If v > 1 we can use the identity in A&S 17.7.7/8
							 | 
						||
| 
								 | 
							
								      // to shift to 0 <= v <= 1.  In contrast to previous
							 | 
						||
| 
								 | 
							
								      // revisions of this header, this identity does now work
							 | 
						||
| 
								 | 
							
								      // but appears not to produce better error rates in 
							 | 
						||
| 
								 | 
							
								      // practice.  Archived here for future reference...
							 | 
						||
| 
								 | 
							
								      //
							 | 
						||
| 
								 | 
							
								      T k2 = k * k;
							 | 
						||
| 
								 | 
							
								      T N = k2 / v;
							 | 
						||
| 
								 | 
							
								      T Nm1 = (v - k2) / v;
							 | 
						||
| 
								 | 
							
								      T p1 = sqrt((-vc) * (1 - k2 / v));
							 | 
						||
| 
								 | 
							
								      T delta = sqrt(1 - k2 * sphi * sphi);
							 | 
						||
| 
								 | 
							
								      //
							 | 
						||
| 
								 | 
							
								      // These next two terms have a large amount of cancellation
							 | 
						||
| 
								 | 
							
								      // so it's not clear if this relation is useable even if
							 | 
						||
| 
								 | 
							
								      // the issues with phi > pi/2 can be fixed:
							 | 
						||
| 
								 | 
							
								      //
							 | 
						||
| 
								 | 
							
								      result = -ellint_pi_imp(N, phi, k, Nm1, pol);
							 | 
						||
| 
								 | 
							
								      result += ellint_f_imp(phi, k, pol);
							 | 
						||
| 
								 | 
							
								      //
							 | 
						||
| 
								 | 
							
								      // This log term gives the complex result when
							 | 
						||
| 
								 | 
							
								      //     n > 1/sin^2(phi)
							 | 
						||
| 
								 | 
							
								      // However that case is dealt with as an error above, 
							 | 
						||
| 
								 | 
							
								      // so we should always get a real result here:
							 | 
						||
| 
								 | 
							
								      //
							 | 
						||
| 
								 | 
							
								      result += log((delta + p1 * tan(phi)) / (delta - p1 * tan(phi))) / (2 * p1);
							 | 
						||
| 
								 | 
							
								      return result;
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								   //
							 | 
						||
| 
								 | 
							
								   // Carlson's algorithm works only for |phi| <= pi/2,
							 | 
						||
| 
								 | 
							
								   // by the time we get here phi should already have been
							 | 
						||
| 
								 | 
							
								   // normalised above.
							 | 
						||
| 
								 | 
							
								   //
							 | 
						||
| 
								 | 
							
								   BOOST_ASSERT(fabs(phi) < constants::half_pi<T>());
							 | 
						||
| 
								 | 
							
								   BOOST_ASSERT(phi >= 0);
							 | 
						||
| 
								 | 
							
								   T x, y, z, p, t;
							 | 
						||
| 
								 | 
							
								   T cosp = cos(phi);
							 | 
						||
| 
								 | 
							
								   x = cosp * cosp;
							 | 
						||
| 
								 | 
							
								   t = sphi * sphi;
							 | 
						||
| 
								 | 
							
								   y = 1 - k * k * t;
							 | 
						||
| 
								 | 
							
								   z = 1;
							 | 
						||
| 
								 | 
							
								   if(v * t < 0.5)
							 | 
						||
| 
								 | 
							
								      p = 1 - v * t;
							 | 
						||
| 
								 | 
							
								   else
							 | 
						||
| 
								 | 
							
								      p = x + vc * t;
							 | 
						||
| 
								 | 
							
								   result = sphi * (ellint_rf_imp(x, y, z, pol) + v * t * ellint_rj_imp(x, y, z, p, pol) / 3);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   return result;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Complete elliptic integral (Legendre form) of the third kind
							 | 
						||
| 
								 | 
							
								template <typename T, typename Policy>
							 | 
						||
| 
								 | 
							
								T ellint_pi_imp(T v, T k, T vc, const Policy& pol)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    // Note arg vc = 1-v, possibly without cancellation errors
							 | 
						||
| 
								 | 
							
								    BOOST_MATH_STD_USING
							 | 
						||
| 
								 | 
							
								    using namespace boost::math::tools;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    static const char* function = "boost::math::ellint_pi<%1%>(%1%,%1%)";
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (abs(k) >= 1)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								       return policies::raise_domain_error<T>(function,
							 | 
						||
| 
								 | 
							
								            "Got k = %1%, function requires |k| <= 1", k, pol);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if(vc <= 0)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								       // Result is complex:
							 | 
						||
| 
								 | 
							
								       return policies::raise_domain_error<T>(function,
							 | 
						||
| 
								 | 
							
								            "Got v = %1%, function requires v < 1", v, pol);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if(v == 0)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								       return (k == 0) ? boost::math::constants::pi<T>() / 2 : ellint_k_imp(k, pol);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if(v < 0)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								       // Apply A&S 17.7.17:
							 | 
						||
| 
								 | 
							
								       T k2 = k * k;
							 | 
						||
| 
								 | 
							
								       T N = (k2 - v) / (1 - v);
							 | 
						||
| 
								 | 
							
								       T Nm1 = (1 - k2) / (1 - v);
							 | 
						||
| 
								 | 
							
								       T result = 0;
							 | 
						||
| 
								 | 
							
								       result = boost::math::detail::ellint_pi_imp(N, k, Nm1, pol);
							 | 
						||
| 
								 | 
							
								       // This next part is split in two to avoid spurious over/underflow:
							 | 
						||
| 
								 | 
							
								       result *= -v / (1 - v);
							 | 
						||
| 
								 | 
							
								       result *= (1 - k2) / (k2 - v);
							 | 
						||
| 
								 | 
							
								       result += ellint_k_imp(k, pol) * k2 / (k2 - v);
							 | 
						||
| 
								 | 
							
								       return result;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    T x = 0;
							 | 
						||
| 
								 | 
							
								    T y = 1 - k * k;
							 | 
						||
| 
								 | 
							
								    T z = 1;
							 | 
						||
| 
								 | 
							
								    T p = vc;
							 | 
						||
| 
								 | 
							
								    T value = ellint_rf_imp(x, y, z, pol) + v * ellint_rj_imp(x, y, z, p, pol) / 3;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return value;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								template <class T1, class T2, class T3>
							 | 
						||
| 
								 | 
							
								inline typename tools::promote_args<T1, T2, T3>::type ellint_3(T1 k, T2 v, T3 phi, const mpl::false_&)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								   return boost::math::ellint_3(k, v, phi, policies::policy<>());
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								template <class T1, class T2, class Policy>
							 | 
						||
| 
								 | 
							
								inline typename tools::promote_args<T1, T2>::type ellint_3(T1 k, T2 v, const Policy& pol, const mpl::true_&)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								   typedef typename tools::promote_args<T1, T2>::type result_type;
							 | 
						||
| 
								 | 
							
								   typedef typename policies::evaluation<result_type, Policy>::type value_type;
							 | 
						||
| 
								 | 
							
								   return policies::checked_narrowing_cast<result_type, Policy>(
							 | 
						||
| 
								 | 
							
								      detail::ellint_pi_imp(
							 | 
						||
| 
								 | 
							
								         static_cast<value_type>(v), 
							 | 
						||
| 
								 | 
							
								         static_cast<value_type>(k),
							 | 
						||
| 
								 | 
							
								         static_cast<value_type>(1-v),
							 | 
						||
| 
								 | 
							
								         pol), "boost::math::ellint_3<%1%>(%1%,%1%)");
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								} // namespace detail
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								template <class T1, class T2, class T3, class Policy>
							 | 
						||
| 
								 | 
							
								inline typename tools::promote_args<T1, T2, T3>::type ellint_3(T1 k, T2 v, T3 phi, const Policy& pol)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								   typedef typename tools::promote_args<T1, T2, T3>::type result_type;
							 | 
						||
| 
								 | 
							
								   typedef typename policies::evaluation<result_type, Policy>::type value_type;
							 | 
						||
| 
								 | 
							
								   return policies::checked_narrowing_cast<result_type, Policy>(
							 | 
						||
| 
								 | 
							
								      detail::ellint_pi_imp(
							 | 
						||
| 
								 | 
							
								         static_cast<value_type>(v), 
							 | 
						||
| 
								 | 
							
								         static_cast<value_type>(phi), 
							 | 
						||
| 
								 | 
							
								         static_cast<value_type>(k),
							 | 
						||
| 
								 | 
							
								         static_cast<value_type>(1-v),
							 | 
						||
| 
								 | 
							
								         pol), "boost::math::ellint_3<%1%>(%1%,%1%,%1%)");
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								template <class T1, class T2, class T3>
							 | 
						||
| 
								 | 
							
								typename detail::ellint_3_result<T1, T2, T3>::type ellint_3(T1 k, T2 v, T3 phi)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								   typedef typename policies::is_policy<T3>::type tag_type;
							 | 
						||
| 
								 | 
							
								   return detail::ellint_3(k, v, phi, tag_type());
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								template <class T1, class T2>
							 | 
						||
| 
								 | 
							
								inline typename tools::promote_args<T1, T2>::type ellint_3(T1 k, T2 v)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								   return ellint_3(k, v, policies::policy<>());
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								}} // namespaces
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#endif // BOOST_MATH_ELLINT_3_HPP
							 | 
						||
| 
								 | 
							
								
							 |