|
| 1 | +// Copyright 2024 Matt Borland |
| 2 | +// Copyright 2024 Christopher Kormanyos |
| 3 | +// Distributed under the Boost Software License, Version 1.0. |
| 4 | +// https://www.boost.org/LICENSE_1_0.txt |
| 5 | + |
| 6 | +#ifndef BOOST_DECIMAL_DETAIL_CMATH_IMPL_EXP_IMPL_HPP |
| 7 | +#define BOOST_DECIMAL_DETAIL_CMATH_IMPL_EXP_IMPL_HPP |
| 8 | + |
| 9 | +#include <boost/decimal/detail/concepts.hpp> |
| 10 | + |
| 11 | +#ifndef BOOST_DECIMAL_BUILD_MODULE |
| 12 | +#include <array> |
| 13 | +#include <cstddef> |
| 14 | +#include <cstdint> |
| 15 | +#endif |
| 16 | + |
| 17 | +namespace boost { |
| 18 | +namespace decimal { |
| 19 | +namespace detail { |
| 20 | + |
| 21 | +template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE T> |
| 22 | +constexpr auto exp_pade_appxroximant(T x) noexcept; |
| 23 | + |
| 24 | +template <> |
| 25 | +constexpr auto exp_pade_appxroximant<decimal32>(decimal32 x) noexcept |
| 26 | +{ |
| 27 | + // TODO: Chris: At 32-bit, reduce the number of coefficients in the Pade appxorimant of the exp() function. |
| 28 | + |
| 29 | + using local_float_t = decimal32; |
| 30 | + |
| 31 | + // PadeApproximant[Exp[x] - 1, {x, 0, {6, 6}}] |
| 32 | + // FullSimplify[%] |
| 33 | + // (84 x (7920 + 240 x^2 + x^4)) |
| 34 | + // / (665280 + x (-332640 + x (75600 + x (-10080 + x (840 + (-42 + x) x))))) |
| 35 | + |
| 36 | + const auto x2 = x * x; |
| 37 | + |
| 38 | + // Use the small-argument Pade approximation having coefficients shown above. |
| 39 | + const local_float_t top = local_float_t { UINT8_C(84), 0 } * x * ( local_float_t { UINT16_C(7920), 0 } + ( local_float_t { UINT8_C(240), 0 } + x2) * x2); |
| 40 | + const local_float_t bot = local_float_t { UINT32_C(665280), 0 } + x * (local_float_t { INT32_C(-332640), 0 } + x * (local_float_t { UINT32_C(75600), 0 } + x * (local_float_t { INT16_C(-10080), 0 } + x * (local_float_t { UINT16_C(840), 0 } + (local_float_t { INT8_C(-42), 0 } + x) * x)))); |
| 41 | + |
| 42 | + return local_float_t { 1 } + (top / bot); |
| 43 | +} |
| 44 | + |
| 45 | +template <> |
| 46 | +constexpr auto exp_pade_appxroximant<decimal64>(decimal64 x) noexcept |
| 47 | +{ |
| 48 | + using local_float_t = decimal64; |
| 49 | + |
| 50 | + // PadeApproximant[Exp[x] - 1, {x, 0, {6, 6}}] |
| 51 | + // FullSimplify[%] |
| 52 | + // (84 x (7920 + 240 x^2 + x^4)) |
| 53 | + // / (665280 + x (-332640 + x (75600 + x (-10080 + x (840 + (-42 + x) x))))) |
| 54 | + |
| 55 | + const auto x2 = x * x; |
| 56 | + |
| 57 | + // Use the small-argument Pade approximation having coefficients shown above. |
| 58 | + const local_float_t top = local_float_t { UINT8_C(84), 0 } * x * ( local_float_t { UINT16_C(7920), 0 } + ( local_float_t { UINT8_C(240), 0 } + x2) * x2); |
| 59 | + const local_float_t bot = local_float_t { UINT32_C(665280), 0 } + x * (local_float_t { INT32_C(-332640), 0 } + x * (local_float_t { UINT32_C(75600), 0 } + x * (local_float_t { INT16_C(-10080), 0 } + x * (local_float_t { UINT16_C(840), 0 } + (local_float_t { INT8_C(-42), 0 } + x) * x)))); |
| 60 | + |
| 61 | + return local_float_t { 1 } + (top / bot); |
| 62 | +} |
| 63 | + |
| 64 | +template <> |
| 65 | +constexpr auto exp_pade_appxroximant<decimal128>(decimal128 x) noexcept |
| 66 | +{ |
| 67 | + // TODO: Chris: At 128-bit, add more coefficients to the Pade appxorimant of the exp() function. |
| 68 | + |
| 69 | + // Compute exp(x) - 1 for x small. |
| 70 | + |
| 71 | + // Use an order-12 Pade approximation of the exponential function. |
| 72 | + // PadeApproximant[Exp[x] - 1, {x, 0, 12, 12}]. |
| 73 | + |
| 74 | + using local_float_t = decimal128; |
| 75 | + |
| 76 | + const local_float_t x2 = (x * x); |
| 77 | + |
| 78 | + const local_float_t top = ((((( local_float_t { boost::decimal::detail::uint128 { UINT64_C(130576843339991), UINT64_C(2348781707059460614) }, -46 } * x2 |
| 79 | + + local_float_t { boost::decimal::detail::uint128 { UINT64_C(502720846858965), UINT64_C(15499169997977266440) }, -43 } ) * x2 |
| 80 | + + local_float_t { boost::decimal::detail::uint128 { UINT64_C(492264253244299), UINT64_C(6469924059228430936) }, -40 } ) * x2 |
| 81 | + + local_float_t { boost::decimal::detail::uint128 { UINT64_C(168354374609550), UINT64_C(6971973999273187690) }, -37 } ) * x2 |
| 82 | + + local_float_t { boost::decimal::detail::uint128 { UINT64_C(196413437044475), UINT64_C(8133969665818718980) }, -35 } ) * x2 |
| 83 | + + local_float_t { boost::decimal::detail::uint128 { UINT64_C(54210108624275), UINT64_C(4089650035136921600) }, -33 } ) |
| 84 | + ; |
| 85 | + |
| 86 | + const local_float_t bot = (((((((((((( local_float_t( +boost::decimal::decimal128 { boost::decimal::detail::uint128 { UINT64_C(418515523525612), UINT64_C(10839100561497421498) }, -49 } ) * x |
| 87 | + + local_float_t( -boost::decimal::decimal128 { boost::decimal::detail::uint128 { UINT64_C(65288421669995), UINT64_C(10397762890384506116) }, -46 } )) * x |
| 88 | + + local_float_t( +boost::decimal::decimal128 { boost::decimal::detail::uint128 { UINT64_C(502720846858965), UINT64_C(15499169997977266440) }, -45 } )) * x |
| 89 | + + local_float_t( -boost::decimal::decimal128 { boost::decimal::detail::uint128 { UINT64_C(251360423429482), UINT64_C(16972957035843409028) }, -43 } )) * x |
| 90 | + + local_float_t( +boost::decimal::decimal128 { boost::decimal::detail::uint128 { UINT64_C(90489752434613), UINT64_C(15702571451232594082) }, -41 } )) * x |
| 91 | + + local_float_t( -boost::decimal::decimal128 { boost::decimal::detail::uint128 { UINT64_C(246132126622149), UINT64_C(12458334066468991276) }, -40 } )) * x |
| 92 | + + local_float_t( +boost::decimal::decimal128 { boost::decimal::detail::uint128 { UINT64_C(516877465906514), UINT64_C(5871083058504374896) }, -39 } )) * x |
| 93 | + + local_float_t( -boost::decimal::decimal128 { boost::decimal::detail::uint128 { UINT64_C(84177187304775), UINT64_C(3485986999636593840) }, -37 } )) * x |
| 94 | + + local_float_t( +boost::decimal::decimal128 { boost::decimal::detail::uint128 { UINT64_C(105221484130968), UINT64_C(18192541804827906022) }, -36 } )) * x |
| 95 | + + local_float_t( -boost::decimal::decimal128 { boost::decimal::detail::uint128 { UINT64_C(98206718522237), UINT64_C(13290356869764135298) }, -35 } )) * x |
| 96 | + + local_float_t( +boost::decimal::decimal128 { boost::decimal::detail::uint128 { UINT64_C(64816434224676), UINT64_C(16519268045002340975) }, -34 } )) * x |
| 97 | + + local_float_t( -boost::decimal::decimal128 { boost::decimal::detail::uint128 { UINT64_C(271050543121376), UINT64_C(2001506101975056384) }, -34 } )) * x |
| 98 | + + local_float_t( +boost::decimal::decimal128 { boost::decimal::detail::uint128 { UINT64_C(54210108624275), UINT64_C(4089650035136921600) }, -33 } )) |
| 99 | + ; |
| 100 | + |
| 101 | + return local_float_t { 1 } + ((x * top) / bot); |
| 102 | +} |
| 103 | + |
| 104 | +} //namespace detail |
| 105 | +} //namespace decimal |
| 106 | +} //namespace boost |
| 107 | + |
| 108 | +#endif //BOOST_DECIMAL_DETAIL_CMATH_IMPL_EXP_IMPL_HPP |
0 commit comments