diff --git a/example/continued_fractions.cpp b/example/continued_fractions.cpp index 852a8e672b..a4e127acec 100644 --- a/example/continued_fractions.cpp +++ b/example/continued_fractions.cpp @@ -122,29 +122,27 @@ inline boost::multiprecision::cpp_complex_50 gamma_Q_as_fraction(const boost::mu return pow(z, a) / (exp(z) * (z - a + 1 + boost::math::tools::continued_fraction_a(f, eps))); } - int main() { using namespace boost::math::tools; //[cf_gr golden_ratio_fraction func; - double gr = continued_fraction_a( + double gr = continued_fraction_b( func, - std::numeric_limits::epsilon()); + std::numeric_limits::epsilon() + ); std::cout << "The golden ratio is: " << gr << std::endl; //] - std::cout << tan(0.5) << std::endl; + std::cout << "tan(0.5)=" << tan(0.5) << std::endl; std::complex arg(3, 2); - std::cout << expint_as_fraction(5, arg) << std::endl; + std::cout << "E_5(3+2i)=" << expint_as_fraction(5, arg) << std::endl; std::complex a(3, 3), z(3, 2); - std::cout << gamma_Q_as_fraction(a, z) << std::endl; + std::cout << "Gamma(3+3i, 3+2i)=" << gamma_Q_as_fraction(a, z) << std::endl; boost::multiprecision::cpp_complex_50 am(3, 3), zm(3, 2); - std::cout << gamma_Q_as_fraction(am, zm) << std::endl; - - return 0; + std::cout << "Gamma(3+3i, 3+2i)=" << gamma_Q_as_fraction(am, zm) << std::endl; } diff --git a/include/boost/math/special_functions/gamma.hpp b/include/boost/math/special_functions/gamma.hpp index 47b4f3d68d..e8e3301b2e 100644 --- a/include/boost/math/special_functions/gamma.hpp +++ b/include/boost/math/special_functions/gamma.hpp @@ -35,6 +35,7 @@ #include #include #include +#include // Only needed for types larger than double #ifndef BOOST_MATH_HAS_GPU_SUPPORT @@ -393,6 +394,29 @@ struct upper_incomplete_gamma_fract } }; +template +struct complex_upper_incomplete_gamma_fract +{ +private: + typedef typename T::value_type scalar_type; + T z, a; + int k; +public: + typedef std::pair result_type; + + complex_upper_incomplete_gamma_fract(T a1, T z1) + : z(z1 - a1 + scalar_type(1)), a(a1), k(0) + { + } + + result_type operator()() + { + ++k; + z += scalar_type(2); + return result_type(scalar_type(k) * (a - scalar_type(k)), z); + } +}; + template BOOST_MATH_GPU_ENABLED inline T upper_gamma_fraction(T a, T z, T eps) { @@ -403,6 +427,15 @@ BOOST_MATH_GPU_ENABLED inline T upper_gamma_fraction(T a, T z, T eps) return 1 / (z - a + 1 + boost::math::tools::continued_fraction_a(f, eps)); } +template +inline std::complex log_upper_gamma_fraction(const std::complex& a, const std::complex& z) +{ + complex_upper_incomplete_gamma_fract > f(a, z); + std::complex eps(std::numeric_limits::epsilon()); + boost::math::uintmax_t max_iter = (boost::math::numeric_limits::max)(); + return a * log(z) - z - boost::math::logaddexpcomplex(log(z - a + T(1)), boost::math::tools::log_continued_fraction_a(f, eps, max_iter)); +} + template struct lower_incomplete_gamma_series { diff --git a/include/boost/math/special_functions/logaddexp.hpp b/include/boost/math/special_functions/logaddexp.hpp index 8949496f6e..bd2db48553 100644 --- a/include/boost/math/special_functions/logaddexp.hpp +++ b/include/boost/math/special_functions/logaddexp.hpp @@ -38,4 +38,31 @@ Real logaddexp(Real x1, Real x2) noexcept return x2 + log1p(exp(temp)); } -}} // Namespace boost::math +template +T logaddexpcomplex(T x1, T x2) noexcept +{ + using std::log; + using std::exp; + using std::abs; + + // Validate inputs first + if (!(boost::math::isfinite)(x1)) + { + return x1; + } + else if (!(boost::math::isfinite)(x2)) + { + return x2; + } + + const T temp = x1 - x2; + + if (std::real(temp) > 0) + { + return x1 + log(1.0 + exp(-temp)); + } + + return x2 + log(1.0 + exp(temp)); +} +} +}// Namespace boost::math diff --git a/include/boost/math/tools/fraction.hpp b/include/boost/math/tools/fraction.hpp index f36d024c40..c9dae7be09 100644 --- a/include/boost/math/tools/fraction.hpp +++ b/include/boost/math/tools/fraction.hpp @@ -18,6 +18,9 @@ #include #include #include +#include +#include +#include namespace boost{ namespace math{ namespace tools{ @@ -159,6 +162,55 @@ BOOST_MATH_GPU_ENABLED inline typename detail::fraction_traits::result_type return f; } +template +BOOST_MATH_GPU_ENABLED inline typename detail::fraction_traits::result_type log_continued_fraction_b_impl(Gen& g, const U& factor, boost::math::uintmax_t& max_terms) + noexcept(BOOST_MATH_IS_FLOAT(typename detail::fraction_traits::result_type) + #ifndef BOOST_MATH_HAS_GPU_SUPPORT + // SYCL can not handle this condition so we only check float on that platform + && noexcept(std::declval()()) + #endif + ) +{ + BOOST_MATH_STD_USING // ADL of std names + + using traits = detail::fraction_traits; + using result_type = typename traits::result_type; + using value_type = typename traits::value_type; + using integer_type = typename integer_scalar_type::type; + using scalar_type = typename scalar_type::type; + + integer_type const zero(0), one(1); + + result_type tiny = detail::tiny_value::get(); + scalar_type terminator = abs(factor); + + value_type v = g(); + + result_type f, C, D, delta; + f = log(traits::b(v)); + if(f == -std::numeric_limits::infinity()) + f = log(tiny); + C = f; + D = log(tiny); + + boost::math::uintmax_t counter(max_terms); + do{ + v = g(); + D = -logaddexp(log(traits::b(v)), log(traits::a(v)) + D); + if(D == -std::numeric_limits::infinity()) + D = log(tiny); + C = logaddexp(log(traits::b(v)), log(traits::a(v)) - C); + if(C == -std::numeric_limits::infinity()) + C = log(tiny); + delta = C + D; + f = f + delta; + }while((abs(delta) > terminator) && --counter); + + max_terms = max_terms - counter; + + return f; +} + } // namespace detail template @@ -219,6 +271,18 @@ BOOST_MATH_GPU_ENABLED inline typename detail::fraction_traits::result_type return detail::continued_fraction_b_impl(g, factor, max_terms); } +template +BOOST_MATH_GPU_ENABLED inline typename detail::fraction_traits::result_type log_continued_fraction_b(Gen& g, const U& factor, boost::math::uintmax_t& max_terms) + noexcept(BOOST_MATH_IS_FLOAT(typename detail::fraction_traits::result_type) + #ifndef BOOST_MATH_HAS_GPU_SUPPORT + && noexcept(std::declval()()) + #endif + ) +{ + return detail::log_continued_fraction_b_impl(g, factor, max_terms); +} + + namespace detail { // @@ -286,6 +350,53 @@ BOOST_MATH_GPU_ENABLED inline typename detail::fraction_traits::result_type return a0/f; } +template +BOOST_MATH_GPU_ENABLED inline typename detail::fraction_traits::result_type log_continued_fraction_a_impl(Gen& g, const U& factor, boost::math::uintmax_t& max_terms) + noexcept(BOOST_MATH_IS_FLOAT(typename detail::fraction_traits::result_type) + #ifndef BOOST_MATH_HAS_GPU_SUPPORT + && noexcept(std::declval()()) + #endif + ) +{ + BOOST_MATH_STD_USING // ADL of std names + + using traits = detail::fraction_traits; + using result_type = typename traits::result_type; + using value_type = typename traits::value_type; + using integer_type = typename integer_scalar_type::type; + using scalar_type = typename scalar_type::type; + + integer_type const zero(0), one(1); + + result_type tiny = detail::tiny_value::get(); + scalar_type terminator = abs(factor); + + value_type v = g(); + + result_type f, C, D, delta, a0; + f = log(traits::b(v)); + a0 = log(traits::a(v)); + if(f == -std::numeric_limits::infinity()) + f = log(tiny); + C = f; + D = log(tiny); + + boost::math::uintmax_t counter(max_terms); + do{ + v = g(); + D = -logaddexpcomplex(log(traits::b(v)), log(traits::a(v)) + D); + if(D == -std::numeric_limits::infinity()) + D = log(tiny); + C = logaddexpcomplex(log(traits::b(v)), log(traits::a(v)) - C); + if(C == -std::numeric_limits::infinity()) + C = log(tiny); + delta = C + D; + f = f + delta; + }while((abs(delta) > terminator) && --counter); + + return a0 - f; +} + } // namespace detail template @@ -347,6 +458,17 @@ BOOST_MATH_GPU_ENABLED inline typename detail::fraction_traits::result_type return detail::continued_fraction_a_impl(g, factor, max_terms); } +template +BOOST_MATH_GPU_ENABLED inline typename detail::fraction_traits::result_type log_continued_fraction_a(Gen& g, const U& factor, boost::math::uintmax_t& max_terms) + noexcept(BOOST_MATH_IS_FLOAT(typename detail::fraction_traits::result_type) + #ifndef BOOST_MATH_HAS_GPU_SUPPORT + && noexcept(std::declval()()) + #endif + ) +{ + return detail::log_continued_fraction_a_impl(g, factor, max_terms); +} + } // namespace tools } // namespace math } // namespace boost