77#define BOOST_DECIMAL_DETAIL_CMATH_IMPL_EXP_IMPL_HPP
88
99#include < boost/decimal/detail/concepts.hpp>
10+ #include < boost/decimal/detail/cmath/impl/taylor_series_result.hpp>
1011
1112#ifndef BOOST_DECIMAL_BUILD_MODULE
1213#include < array>
@@ -18,32 +19,76 @@ namespace boost {
1819namespace decimal {
1920namespace detail {
2021
22+ namespace exp_detail {
23+
24+ template <bool b>
25+ struct exp_table_imp
26+ {
27+ private:
28+ using d128_coeffs_t = std::array<decimal128, 17 >;
29+
30+ public:
31+ static constexpr d128_coeffs_t d128_coeffs =
32+ {{
33+ // Series[Exp[x] - 1, {x, 0, 18}]
34+ // (1), // * x
35+ ::boost::decimal::decimal128 { 5 , -1 }, // * x^2
36+ ::boost::decimal::decimal128 { boost::decimal::detail::uint128 { UINT64_C (90350181040458 ), UINT64_C (12964998083131386532 ) }, -34 },
37+ ::boost::decimal::decimal128 { boost::decimal::detail::uint128 { UINT64_C (225875452601146 ), UINT64_C (13965751134118914724 ) }, -35 },
38+ ::boost::decimal::decimal128 { boost::decimal::detail::uint128 { UINT64_C (451750905202293 ), UINT64_C (9484758194528277842 ) }, -36 },
39+ ::boost::decimal::decimal128 { boost::decimal::detail::uint128 { UINT64_C (75291817533715 ), UINT64_C (10804165069276155440 ) }, -36 },
40+ ::boost::decimal::decimal128 { boost::decimal::detail::uint128 { UINT64_C (107559739333879 ), UINT64_C (7528774067376128516 ) }, -37 },
41+ ::boost::decimal::decimal128 { boost::decimal::detail::uint128 { UINT64_C (134449674167349 ), UINT64_C (4799281565792772746 ) }, -38 },
42+ ::boost::decimal::decimal128 { boost::decimal::detail::uint128 { UINT64_C (149388526852610 ), UINT64_C (5332535073103080820 ) }, -39 },
43+ ::boost::decimal::decimal128 { boost::decimal::detail::uint128 { UINT64_C (149388526852610 ), UINT64_C (5332535073103080820 ) }, -40 },
44+ ::boost::decimal::decimal128 { boost::decimal::detail::uint128 { UINT64_C (135807751684191 ), UINT64_C (3170782423392841514 ) }, -41 },
45+ ::boost::decimal::decimal128 { boost::decimal::detail::uint128 { UINT64_C (113173126403492 ), UINT64_C (11865690723015477068 ) }, -42 },
46+ ::boost::decimal::decimal128 { boost::decimal::detail::uint128 { UINT64_C (87056251079609 ), UINT64_C (13384395342406417346 ) }, -43 },
47+ ::boost::decimal::decimal128 { boost::decimal::detail::uint128 { UINT64_C (62183036485435 ), UINT64_C (9560282387433155251 ) }, -44 },
48+ ::boost::decimal::decimal128 { boost::decimal::detail::uint128 { UINT64_C (414553576569570 ), UINT64_C (2246069003855862950 ) }, -46 },
49+ ::boost::decimal::decimal128 { boost::decimal::detail::uint128 { UINT64_C (259095985355981 ), UINT64_C (6015479145837302244 ) }, -47 },
50+ ::boost::decimal::decimal128 { boost::decimal::detail::uint128 { UINT64_C (152409403150577 ), UINT64_C (4623619737181327888 ) }, -48 },
51+ ::boost::decimal::decimal128 { boost::decimal::detail::uint128 { UINT64_C (84671890639209 ), UINT64_C (10767230553416093986 ) }, -49 },
52+ }};
53+ };
54+
55+ #if !(defined(__cpp_inline_variables) && __cpp_inline_variables >= 201606L) && (!defined(_MSC_VER) || _MSC_VER != 1900)
56+
57+ template <bool b>
58+ constexpr typename exp_table_imp<b>::d128_coeffs_t exp_table_imp<b>::d128_coeffs;
59+
60+ #endif
61+
62+ } // namespace exp_detail
63+
64+ using exp_table = exp_detail::exp_table_imp<true >;
65+
2166template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE T>
22- constexpr auto exp_pade_appxroximant (T x) noexcept ;
67+ constexpr auto exp_pade_appxroximant_or_series (T x) noexcept ;
2368
2469template <>
25- constexpr auto exp_pade_appxroximant <decimal32>(decimal32 x) noexcept
70+ constexpr auto exp_pade_appxroximant_or_series <decimal32>(decimal32 x) noexcept
2671{
27- // TODO: Chris: At 32-bit, reduce the number of coefficients in the Pade appxorimant of the exp() function.
28-
2972 using local_float_t = decimal32;
3073
31- // PadeApproximant[Exp[x] - 1, {x, 0, {6, 6 }}]
74+ // PadeApproximant[Exp[x] - 1, {x, 0, {3, 4 }}]
3275 // FullSimplify[%]
33- // (84 x (7920 + 240 x^2 + x^4 ))
34- // / (665280 + x (-332640 + x (75600 + x (-10080 + x (840 + (-42 + x ) x)) )))
76+ // (40 x (42 + x^2))
77+ // / (1680 + x (-840 + x (180 + (-20 + x) x)))
3578
3679 const auto x2 = x * x;
3780
3881 // 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)))) ;
82+ const local_float_t top { local_float_t { UINT8_C (40 ), 0 } * x * (local_float_t { UINT8_C (42 ), 0 } + x2) } ;
83+ const local_float_t bot { local_float_t { UINT16_C ( 1680 ), 0 } + x * (local_float_t { INT16_C (-840 ), 0 } + x * (local_float_t { UINT8_C ( 180 ), 0 } + (local_float_t { INT8_C (-20 ), 0 } + x) * x)) } ;
4184
42- return local_float_t { 1 } + (top / bot);
85+ constexpr local_float_t one { 1 };
86+
87+ return one + (top / bot);
4388}
4489
4590template <>
46- constexpr auto exp_pade_appxroximant <decimal64>(decimal64 x) noexcept
91+ constexpr auto exp_pade_appxroximant_or_series <decimal64>(decimal64 x) noexcept
4792{
4893 using local_float_t = decimal64;
4994
@@ -58,54 +103,38 @@ constexpr auto exp_pade_appxroximant<decimal64>(decimal64 x) noexcept
58103 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);
59104 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))));
60105
61- return local_float_t { 1 } + (top / bot);
106+ constexpr local_float_t one { 1 };
107+
108+ return one + (top / bot);
62109}
63110
64111template <>
65- constexpr auto exp_pade_appxroximant <decimal128>(decimal128 x) noexcept
112+ constexpr auto exp_pade_appxroximant_or_series <decimal128>(decimal128 x) noexcept
66113{
67114 // Compute exp(x) - 1 for x small.
68-
69- // Use an order-12 Pade approximation of the exponential function.
70- // PadeApproximant[Exp[x] - 1, {x, 0, 12, 12}].
115+ // Use argument scaling in combination with a Taylor series expansion to order-18.
71116
72117 using local_float_t = decimal128;
73118
74119 // Rescale the argument even further (and note the three squarings below).
75120 x /= 8 ;
76121
77- const local_float_t x2 = (x * x);
78-
79- const local_float_t top = ((((( local_float_t { boost::decimal::detail::uint128 { UINT64_C (130576843339991 ), UINT64_C (2348781707059460614 ) }, -46 } * x2
80- + local_float_t { boost::decimal::detail::uint128 { UINT64_C (502720846858965 ), UINT64_C (15499169997977266440 ) }, -43 } ) * x2
81- + local_float_t { boost::decimal::detail::uint128 { UINT64_C (492264253244299 ), UINT64_C (6469924059228430936 ) }, -40 } ) * x2
82- + local_float_t { boost::decimal::detail::uint128 { UINT64_C (168354374609550 ), UINT64_C (6971973999273187690 ) }, -37 } ) * x2
83- + local_float_t { boost::decimal::detail::uint128 { UINT64_C (196413437044475 ), UINT64_C (8133969665818718980 ) }, -35 } ) * x2
84- + local_float_t { boost::decimal::detail::uint128 { UINT64_C (54210108624275 ), UINT64_C (4089650035136921600 ) }, -33 } )
85- ;
86-
87- const local_float_t bot = (((((((((((( local_float_t ( +boost::decimal::decimal128 { boost::decimal::detail::uint128 { UINT64_C (418515523525612 ), UINT64_C (10839100561497421498 ) }, -49 } ) * x
88- + local_float_t ( -boost::decimal::decimal128 { boost::decimal::detail::uint128 { UINT64_C (65288421669995 ), UINT64_C (10397762890384506116 ) }, -46 } )) * x
89- + local_float_t ( +boost::decimal::decimal128 { boost::decimal::detail::uint128 { UINT64_C (502720846858965 ), UINT64_C (15499169997977266440 ) }, -45 } )) * x
90- + local_float_t ( -boost::decimal::decimal128 { boost::decimal::detail::uint128 { UINT64_C (251360423429482 ), UINT64_C (16972957035843409028 ) }, -43 } )) * x
91- + local_float_t ( +boost::decimal::decimal128 { boost::decimal::detail::uint128 { UINT64_C (90489752434613 ), UINT64_C (15702571451232594082 ) }, -41 } )) * x
92- + local_float_t ( -boost::decimal::decimal128 { boost::decimal::detail::uint128 { UINT64_C (246132126622149 ), UINT64_C (12458334066468991276 ) }, -40 } )) * x
93- + local_float_t ( +boost::decimal::decimal128 { boost::decimal::detail::uint128 { UINT64_C (516877465906514 ), UINT64_C (5871083058504374896 ) }, -39 } )) * x
94- + local_float_t ( -boost::decimal::decimal128 { boost::decimal::detail::uint128 { UINT64_C (84177187304775 ), UINT64_C (3485986999636593840 ) }, -37 } )) * x
95- + local_float_t ( +boost::decimal::decimal128 { boost::decimal::detail::uint128 { UINT64_C (105221484130968 ), UINT64_C (18192541804827906022 ) }, -36 } )) * x
96- + local_float_t ( -boost::decimal::decimal128 { boost::decimal::detail::uint128 { UINT64_C (98206718522237 ), UINT64_C (13290356869764135298 ) }, -35 } )) * x
97- + local_float_t ( +boost::decimal::decimal128 { boost::decimal::detail::uint128 { UINT64_C (64816434224676 ), UINT64_C (16519268045002340975 ) }, -34 } )) * x
98- + local_float_t ( -boost::decimal::decimal128 { boost::decimal::detail::uint128 { UINT64_C (271050543121376 ), UINT64_C (2001506101975056384 ) }, -34 } )) * x
99- + local_float_t ( +boost::decimal::decimal128 { boost::decimal::detail::uint128 { UINT64_C (54210108624275 ), UINT64_C (4089650035136921600 ) }, -33 } ))
100- ;
101-
102- local_float_t result { local_float_t { 1 } + ((x * top) / bot) };
122+ constexpr local_float_t one { 1 , 0 };
103123
104- result *= result;
124+ // Note: The Taylor series expansion begins with coefficients of order-2.
125+ // So we need to multiply by x^2 and add the two skipped terms (1 + x).
126+
127+ local_float_t
128+ result
129+ {
130+ one + (x * (one + (x * taylor_series_result (x, exp_table::d128_coeffs))))
131+ };
132+
133+ // Scale up with three squarings in order to obtain the result.
105134 result *= result;
106135 result *= result;
107136
108- return result;
137+ return result *= result ;
109138}
110139
111140} // namespace detail
0 commit comments