diff options
Diffstat (limited to 'boost/math/special_functions/detail/bessel_jy_asym.hpp')
-rw-r--r-- | boost/math/special_functions/detail/bessel_jy_asym.hpp | 176 |
1 files changed, 33 insertions, 143 deletions
diff --git a/boost/math/special_functions/detail/bessel_jy_asym.hpp b/boost/math/special_functions/detail/bessel_jy_asym.hpp index 0021f8c86a..81f6238e58 100644 --- a/boost/math/special_functions/detail/bessel_jy_asym.hpp +++ b/boost/math/special_functions/detail/bessel_jy_asym.hpp @@ -21,61 +21,6 @@ namespace boost{ namespace math{ namespace detail{ template <class T> -inline T asymptotic_bessel_j_large_x_P(T v, T x) -{ - // A&S 9.2.9 - T s = 1; - T mu = 4 * v * v; - T ez2 = 8 * x; - ez2 *= ez2; - s -= (mu-1) * (mu-9) / (2 * ez2); - s += (mu-1) * (mu-9) * (mu-25) * (mu - 49) / (24 * ez2 * ez2); - return s; -} - -template <class T> -inline T asymptotic_bessel_j_large_x_Q(T v, T x) -{ - // A&S 9.2.10 - T s = 0; - T mu = 4 * v * v; - T ez = 8*x; - s += (mu-1) / ez; - s -= (mu-1) * (mu-9) * (mu-25) / (6 * ez*ez*ez); - return s; -} - -template <class T> -inline T asymptotic_bessel_j_large_x(T v, T x) -{ - // - // See http://functions.wolfram.com/BesselAiryStruveFunctions/BesselJ/06/02/02/0001/ - // - // Also A&S 9.2.5 - // - BOOST_MATH_STD_USING // ADL of std names - T chi = fabs(x) - constants::pi<T>() * (2 * v + 1) / 4; - return sqrt(2 / (constants::pi<T>() * x)) - * (asymptotic_bessel_j_large_x_P(v, x) * cos(chi) - - asymptotic_bessel_j_large_x_Q(v, x) * sin(chi)); -} - -template <class T> -inline T asymptotic_bessel_y_large_x(T v, T x) -{ - // - // See http://functions.wolfram.com/BesselAiryStruveFunctions/BesselJ/06/02/02/0001/ - // - // Also A&S 9.2.5 - // - BOOST_MATH_STD_USING // ADL of std names - T chi = fabs(x) - constants::pi<T>() * (2 * v + 1) / 4; - return sqrt(2 / (constants::pi<T>() * x)) - * (asymptotic_bessel_j_large_x_P(v, x) * sin(chi) - - asymptotic_bessel_j_large_x_Q(v, x) * cos(chi)); -} - -template <class T> inline T asymptotic_bessel_amplitude(T v, T x) { // Calculate the amplitude of J(v, x) and Y(v, x) for large @@ -99,13 +44,14 @@ T asymptotic_bessel_phase_mx(T v, T x) // // Calculate the phase of J(v, x) and Y(v, x) for large x. // See A&S 9.2.29. - // Note that the result returned is the phase less x. + // Note that the result returned is the phase less (x - PI(v/2 + 1/4)) + // which we'll factor in later when we calculate the sines/cosines of the result: // T mu = 4 * v * v; T denom = 4 * x; T denom_mult = denom * denom; - T s = -constants::pi<T>() * (v / 2 + 0.25f); + T s = 0; s += (mu - 1) / (2 * denom); denom *= denom_mult; s += (mu - 1) * (mu - 25) / (6 * denom); @@ -127,10 +73,16 @@ inline T asymptotic_bessel_y_large_x_2(T v, T x) BOOST_MATH_INSTRUMENT_VARIABLE(ampl); BOOST_MATH_INSTRUMENT_VARIABLE(phase); // - // Calculate the sine of the phase, using: - // sin(x+p) = sin(x)cos(p) + cos(x)sin(p) + // Calculate the sine of the phase, using + // sine/cosine addition rules to factor in + // the x - PI(v/2 + 1/4) term not added to the + // phase when we calculated it. // - T sin_phase = sin(phase) * cos(x) + cos(phase) * sin(x); + T cx = cos(x); + T sx = sin(x); + T ci = cos_pi(v / 2 + 0.25f); + T si = sin_pi(v / 2 + 0.25f); + T sin_phase = sin(phase) * (cx * ci + sx * si) + cos(phase) * (sx * ci - cx * si); BOOST_MATH_INSTRUMENT_CODE(sin(phase)); BOOST_MATH_INSTRUMENT_CODE(cos(x)); BOOST_MATH_INSTRUMENT_CODE(cos(phase)); @@ -149,101 +101,39 @@ inline T asymptotic_bessel_j_large_x_2(T v, T x) BOOST_MATH_INSTRUMENT_VARIABLE(ampl); BOOST_MATH_INSTRUMENT_VARIABLE(phase); // - // Calculate the sine of the phase, using: - // cos(x+p) = cos(x)cos(p) - sin(x)sin(p) + // Calculate the sine of the phase, using + // sine/cosine addition rules to factor in + // the x - PI(v/2 + 1/4) term not added to the + // phase when we calculated it. // BOOST_MATH_INSTRUMENT_CODE(cos(phase)); BOOST_MATH_INSTRUMENT_CODE(cos(x)); BOOST_MATH_INSTRUMENT_CODE(sin(phase)); BOOST_MATH_INSTRUMENT_CODE(sin(x)); - T sin_phase = cos(phase) * cos(x) - sin(phase) * sin(x); + T cx = cos(x); + T sx = sin(x); + T ci = cos_pi(v / 2 + 0.25f); + T si = sin_pi(v / 2 + 0.25f); + T sin_phase = cos(phase) * (cx * ci + sx * si) - sin(phase) * (sx * ci - cx * si); BOOST_MATH_INSTRUMENT_VARIABLE(sin_phase); return sin_phase * ampl; } -// -// Various limits for the J and Y asymptotics -// (the asympotic expansions are safe to use if -// x is less than the limit given). -// We assume that if we don't use these expansions then the -// error will likely be >100eps, so the limits given are chosen -// to lead to < 100eps truncation error. -// template <class T> -inline T asymptotic_bessel_y_limit(const mpl::int_<0>&) +inline bool asymptotic_bessel_large_x_limit(const T& v, const T& x) { - // default case: BOOST_MATH_STD_USING - return 2.25 / pow(100 * tools::epsilon<T>() / T(0.001f), T(0.2f)); -} -template <class T> -inline T asymptotic_bessel_y_limit(const mpl::int_<53>&) -{ - // double case: - return 304 /*780*/; -} -template <class T> -inline T asymptotic_bessel_y_limit(const mpl::int_<64>&) -{ - // 80-bit extended-double case: - return 1552 /*3500*/; -} -template <class T> -inline T asymptotic_bessel_y_limit(const mpl::int_<113>&) -{ - // 128-bit long double case: - return 1245243 /*3128000*/; -} - -template <class T, class Policy> -struct bessel_asymptotic_tag -{ - typedef typename policies::precision<T, Policy>::type precision_type; - typedef typename mpl::if_< - mpl::or_< - mpl::equal_to<precision_type, mpl::int_<0> >, - mpl::greater<precision_type, mpl::int_<113> > >, - mpl::int_<0>, - typename mpl::if_< - mpl::greater<precision_type, mpl::int_<64> >, - mpl::int_<113>, - typename mpl::if_< - mpl::greater<precision_type, mpl::int_<53> >, - mpl::int_<64>, - mpl::int_<53> - >::type - >::type - >::type type; -}; - -template <class T> -inline T asymptotic_bessel_j_limit(const T& v, const mpl::int_<0>&) -{ - // default case: - BOOST_MATH_STD_USING - T v2 = (std::max)(T(3), T(v * v)); - return v2 / pow(100 * tools::epsilon<T>() / T(2e-5f), T(0.17f)); -} -template <class T> -inline T asymptotic_bessel_j_limit(const T& v, const mpl::int_<53>&) -{ - // double case: - T v2 = (std::max)(T(3), T(v * v)); - return v2 * 33 /*73*/; -} -template <class T> -inline T asymptotic_bessel_j_limit(const T& v, const mpl::int_<64>&) -{ - // 80-bit extended-double case: - T v2 = (std::max)(T(3), T(v * v)); - return v2 * 121 /*266*/; -} -template <class T> -inline T asymptotic_bessel_j_limit(const T& v, const mpl::int_<113>&) -{ - // 128-bit long double case: - T v2 = (std::max)(T(3), T(v * v)); - return v2 * 39154 /*85700*/; + // + // Determines if x is large enough compared to v to take the asymptotic + // forms above. From A&S 9.2.28 we require: + // v < x * eps^1/8 + // and from A&S 9.2.29 we require: + // v^12/10 < 1.5 * x * eps^1/10 + // using the former seems to work OK in practice with broadly similar + // error rates either side of the divide for v < 10000. + // At double precision eps^1/8 ~= 0.01. + // + return (std::max)(T(fabs(v)), T(1)) < x * sqrt(tools::forth_root_epsilon<T>()); } template <class T, class Policy> |