X-Git-Url: https://git.donarmstrong.com/?p=rsem.git;a=blobdiff_plain;f=boost%2Fmath%2Fspecial_functions%2Fellint_rd.hpp;fp=boost%2Fmath%2Fspecial_functions%2Fellint_rd.hpp;h=61014d386608a749687a4d2fec9388f5d1fb149a;hp=0000000000000000000000000000000000000000;hb=2d71eb92104693ca9baa5a2e1c23eeca776d8fd3;hpb=da57529b92adbb7ae74a89861cb39fb35ac7c62d diff --git a/boost/math/special_functions/ellint_rd.hpp b/boost/math/special_functions/ellint_rd.hpp new file mode 100644 index 0000000..61014d3 --- /dev/null +++ b/boost/math/special_functions/ellint_rd.hpp @@ -0,0 +1,130 @@ +// Copyright (c) 2006 Xiaogang Zhang +// 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 slightly to fit into the +// Boost.Math conceptual framework better. + +#ifndef BOOST_MATH_ELLINT_RD_HPP +#define BOOST_MATH_ELLINT_RD_HPP + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include + +// Carlson's elliptic integral of the second kind +// R_D(x, y, z) = R_J(x, y, z, z) = 1.5 * \int_{0}^{\infty} [(t+x)(t+y)]^{-1/2} (t+z)^{-3/2} dt +// Carlson, Numerische Mathematik, vol 33, 1 (1979) + +namespace boost { namespace math { namespace detail{ + +template +T ellint_rd_imp(T x, T y, T z, const Policy& pol) +{ + T value, u, lambda, sigma, factor, tolerance; + T X, Y, Z, EA, EB, EC, ED, EE, S1, S2; + unsigned long k; + + BOOST_MATH_STD_USING + using namespace boost::math::tools; + + static const char* function = "boost::math::ellint_rd<%1%>(%1%,%1%,%1%)"; + + if (x < 0) + { + return policies::raise_domain_error(function, + "Argument x must be >= 0, but got %1%", x, pol); + } + if (y < 0) + { + return policies::raise_domain_error(function, + "Argument y must be >= 0, but got %1%", y, pol); + } + if (z <= 0) + { + return policies::raise_domain_error(function, + "Argument z must be > 0, but got %1%", z, pol); + } + if (x + y == 0) + { + return policies::raise_domain_error(function, + "At most one argument can be zero, but got, x + y = %1%", x+y, pol); + } + + // error scales as the 6th power of tolerance + tolerance = pow(tools::epsilon() / 3, T(1)/6); + + // duplication + sigma = 0; + factor = 1; + k = 1; + do + { + u = (x + y + z + z + z) / 5; + X = (u - x) / u; + Y = (u - y) / u; + Z = (u - z) / u; + if ((tools::max)(abs(X), abs(Y), abs(Z)) < tolerance) + break; + T sx = sqrt(x); + T sy = sqrt(y); + T sz = sqrt(z); + lambda = sy * (sx + sz) + sz * sx; //sqrt(x * y) + sqrt(y * z) + sqrt(z * x); + sigma += factor / (sz * (z + lambda)); + factor /= 4; + x = (x + lambda) / 4; + y = (y + lambda) / 4; + z = (z + lambda) / 4; + ++k; + } + while(k < policies::get_max_series_iterations()); + + // Check to see if we gave up too soon: + policies::check_series_iterations(function, k, pol); + + // Taylor series expansion to the 5th order + EA = X * Y; + EB = Z * Z; + EC = EA - EB; + ED = EA - 6 * EB; + EE = ED + EC + EC; + S1 = ED * (ED * T(9) / 88 - Z * EE * T(9) / 52 - T(3) / 14); + S2 = Z * (EE / 6 + Z * (-EC * T(9) / 22 + Z * EA * T(3) / 26)); + value = 3 * sigma + factor * (1 + S1 + S2) / (u * sqrt(u)); + + return value; +} + +} // namespace detail + +template +inline typename tools::promote_args::type + ellint_rd(T1 x, T2 y, T3 z, const Policy& pol) +{ + typedef typename tools::promote_args::type result_type; + typedef typename policies::evaluation::type value_type; + return policies::checked_narrowing_cast( + detail::ellint_rd_imp( + static_cast(x), + static_cast(y), + static_cast(z), pol), "boost::math::ellint_rd<%1%>(%1%,%1%,%1%)"); +} + +template +inline typename tools::promote_args::type + ellint_rd(T1 x, T2 y, T3 z) +{ + return ellint_rd(x, y, z, policies::policy<>()); +} + +}} // namespaces + +#endif // BOOST_MATH_ELLINT_RD_HPP +