X-Git-Url: https://git.donarmstrong.com/?p=rsem.git;a=blobdiff_plain;f=boost%2Fmath%2Fspecial_functions%2Fellint_rf.hpp;fp=boost%2Fmath%2Fspecial_functions%2Fellint_rf.hpp;h=ac5725783aaa9315490c86ecf84d08fb8a030265;hp=0000000000000000000000000000000000000000;hb=2d71eb92104693ca9baa5a2e1c23eeca776d8fd3;hpb=da57529b92adbb7ae74a89861cb39fb35ac7c62d diff --git a/boost/math/special_functions/ellint_rf.hpp b/boost/math/special_functions/ellint_rf.hpp new file mode 100644 index 0000000..ac57257 --- /dev/null +++ b/boost/math/special_functions/ellint_rf.hpp @@ -0,0 +1,132 @@ +// 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 to fit into the +// Boost.Math conceptual framework better, and to handle +// types longer than 80-bit reals. +// +#ifndef BOOST_MATH_ELLINT_RF_HPP +#define BOOST_MATH_ELLINT_RF_HPP + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include + +#include + +// Carlson's elliptic integral of the first kind +// R_F(x, y, z) = 0.5 * \int_{0}^{\infty} [(t+x)(t+y)(t+z)]^{-1/2} dt +// Carlson, Numerische Mathematik, vol 33, 1 (1979) + +namespace boost { namespace math { namespace detail{ + +template +T ellint_rf_imp(T x, T y, T z, const Policy& pol) +{ + T value, X, Y, Z, E2, E3, u, lambda, tolerance; + unsigned long k; + + BOOST_MATH_STD_USING + using namespace boost::math::tools; + + static const char* function = "boost::math::ellint_rf<%1%>(%1%,%1%,%1%)"; + + if (x < 0 || y < 0 || z < 0) + { + return policies::raise_domain_error(function, + "domain error, all arguments must be non-negative, " + "only sensible result is %1%.", + std::numeric_limits::quiet_NaN(), pol); + } + if (x + y == 0 || y + z == 0 || z + x == 0) + { + return policies::raise_domain_error(function, + "domain error, at most one argument can be zero, " + "only sensible result is %1%.", + std::numeric_limits::quiet_NaN(), pol); + } + + // Carlson scales error as the 6th power of tolerance, + // but this seems not to work for types larger than + // 80-bit reals, this heuristic seems to work OK: + if(policies::digits() > 64) + { + tolerance = pow(tools::epsilon(), T(1)/4.25f); + BOOST_MATH_INSTRUMENT_VARIABLE(tolerance); + } + else + { + tolerance = pow(4*tools::epsilon(), T(1)/6); + BOOST_MATH_INSTRUMENT_VARIABLE(tolerance); + } + + // duplication + k = 1; + do + { + u = (x + y + z) / 3; + X = (u - x) / u; + Y = (u - y) / u; + Z = (u - z) / u; + + // Termination condition: + 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; + 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); + BOOST_MATH_INSTRUMENT_VARIABLE(k); + + // Taylor series expansion to the 5th order + E2 = X * Y - Z * Z; + E3 = X * Y * Z; + value = (1 + E2*(E2/24 - E3*T(3)/44 - T(0.1)) + E3/14) / sqrt(u); + BOOST_MATH_INSTRUMENT_VARIABLE(value); + + return value; +} + +} // namespace detail + +template +inline typename tools::promote_args::type + ellint_rf(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_rf_imp( + static_cast(x), + static_cast(y), + static_cast(z), pol), "boost::math::ellint_rf<%1%>(%1%,%1%,%1%)"); +} + +template +inline typename tools::promote_args::type + ellint_rf(T1 x, T2 y, T3 z) +{ + return ellint_rf(x, y, z, policies::policy<>()); +} + +}} // namespaces + +#endif // BOOST_MATH_ELLINT_RF_HPP +