expm1.hpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. // (C) Copyright John Maddock 2006.
  2. // Use, modification and distribution are subject to the
  3. // Boost Software License, Version 1.0. (See accompanying file
  4. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. #ifndef BOOST_MATH_EXPM1_INCLUDED
  6. #define BOOST_MATH_EXPM1_INCLUDED
  7. #ifdef _MSC_VER
  8. #pragma once
  9. #endif
  10. #include <cmath>
  11. #include <cstdint>
  12. #include <limits>
  13. #include <boost/math/tools/config.hpp>
  14. #include <boost/math/tools/series.hpp>
  15. #include <boost/math/tools/precision.hpp>
  16. #include <boost/math/tools/big_constant.hpp>
  17. #include <boost/math/policies/error_handling.hpp>
  18. #include <boost/math/tools/rational.hpp>
  19. #include <boost/math/special_functions/math_fwd.hpp>
  20. #include <boost/math/tools/assert.hpp>
  21. #if defined(__GNUC__) && defined(BOOST_MATH_USE_FLOAT128)
  22. //
  23. // This is the only way we can avoid
  24. // warning: non-standard suffix on floating constant [-Wpedantic]
  25. // when building with -Wall -pedantic. Neither __extension__
  26. // nor #pragma diagnostic ignored work :(
  27. //
  28. #pragma GCC system_header
  29. #endif
  30. namespace boost{ namespace math{
  31. namespace detail
  32. {
  33. // Functor expm1_series returns the next term in the Taylor series
  34. // x^k / k!
  35. // each time that operator() is invoked.
  36. //
  37. template <class T>
  38. struct expm1_series
  39. {
  40. typedef T result_type;
  41. expm1_series(T x)
  42. : k(0), m_x(x), m_term(1) {}
  43. T operator()()
  44. {
  45. ++k;
  46. m_term *= m_x;
  47. m_term /= k;
  48. return m_term;
  49. }
  50. int count()const
  51. {
  52. return k;
  53. }
  54. private:
  55. int k;
  56. const T m_x;
  57. T m_term;
  58. expm1_series(const expm1_series&) = delete;
  59. expm1_series& operator=(const expm1_series&) = delete;
  60. };
  61. template <class T, class Policy, class tag>
  62. struct expm1_initializer
  63. {
  64. struct init
  65. {
  66. init()
  67. {
  68. do_init(tag());
  69. }
  70. template <int N>
  71. static void do_init(const std::integral_constant<int, N>&){}
  72. static void do_init(const std::integral_constant<int, 64>&)
  73. {
  74. expm1(T(0.5));
  75. }
  76. static void do_init(const std::integral_constant<int, 113>&)
  77. {
  78. expm1(T(0.5));
  79. }
  80. void force_instantiate()const{}
  81. };
  82. static const init initializer;
  83. static void force_instantiate()
  84. {
  85. initializer.force_instantiate();
  86. }
  87. };
  88. template <class T, class Policy, class tag>
  89. const typename expm1_initializer<T, Policy, tag>::init expm1_initializer<T, Policy, tag>::initializer;
  90. //
  91. // Algorithm expm1 is part of C99, but is not yet provided by many compilers.
  92. //
  93. // This version uses a Taylor series expansion for 0.5 > |x| > epsilon.
  94. //
  95. template <class T, class Policy>
  96. T expm1_imp(T x, const std::integral_constant<int, 0>&, const Policy& pol)
  97. {
  98. BOOST_MATH_STD_USING
  99. T a = fabs(x);
  100. if((boost::math::isnan)(a))
  101. {
  102. return policies::raise_domain_error<T>("boost::math::expm1<%1%>(%1%)", "expm1 requires a finite argument, but got %1%", a, pol);
  103. }
  104. if(a > T(0.5f))
  105. {
  106. if(a >= tools::log_max_value<T>())
  107. {
  108. if(x > 0)
  109. return policies::raise_overflow_error<T>("boost::math::expm1<%1%>(%1%)", nullptr, pol);
  110. return -1;
  111. }
  112. return exp(x) - T(1);
  113. }
  114. if(a < tools::epsilon<T>())
  115. return x;
  116. detail::expm1_series<T> s(x);
  117. std::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
  118. T result = tools::sum_series(s, policies::get_epsilon<T, Policy>(), max_iter);
  119. policies::check_series_iterations<T>("boost::math::expm1<%1%>(%1%)", max_iter, pol);
  120. return result;
  121. }
  122. template <class T, class P>
  123. T expm1_imp(T x, const std::integral_constant<int, 53>&, const P& pol)
  124. {
  125. BOOST_MATH_STD_USING
  126. T a = fabs(x);
  127. if(a > T(0.5L))
  128. {
  129. if(a >= tools::log_max_value<T>())
  130. {
  131. if(x > 0)
  132. return policies::raise_overflow_error<T>("boost::math::expm1<%1%>(%1%)", nullptr, pol);
  133. return -1;
  134. }
  135. return exp(x) - T(1);
  136. }
  137. if(a < tools::epsilon<T>())
  138. return x;
  139. static const float Y = 0.10281276702880859e1f;
  140. static const T n[] = { static_cast<T>(-0.28127670288085937e-1), static_cast<T>(0.51278186299064534e0), static_cast<T>(-0.6310029069350198e-1), static_cast<T>(0.11638457975729296e-1), static_cast<T>(-0.52143390687521003e-3), static_cast<T>(0.21491399776965688e-4) };
  141. static const T d[] = { 1, static_cast<T>(-0.45442309511354755e0), static_cast<T>(0.90850389570911714e-1), static_cast<T>(-0.10088963629815502e-1), static_cast<T>(0.63003407478692265e-3), static_cast<T>(-0.17976570003654402e-4) };
  142. T result = x * Y + x * tools::evaluate_polynomial(n, x) / tools::evaluate_polynomial(d, x);
  143. return result;
  144. }
  145. template <class T, class P>
  146. T expm1_imp(T x, const std::integral_constant<int, 64>&, const P& pol)
  147. {
  148. BOOST_MATH_STD_USING
  149. T a = fabs(x);
  150. if(a > T(0.5L))
  151. {
  152. if(a >= tools::log_max_value<T>())
  153. {
  154. if(x > 0)
  155. return policies::raise_overflow_error<T>("boost::math::expm1<%1%>(%1%)", nullptr, pol);
  156. return -1;
  157. }
  158. return exp(x) - T(1);
  159. }
  160. if(a < tools::epsilon<T>())
  161. return x;
  162. static const float Y = 0.10281276702880859375e1f;
  163. static const T n[] = {
  164. BOOST_MATH_BIG_CONSTANT(T, 64, -0.281276702880859375e-1),
  165. BOOST_MATH_BIG_CONSTANT(T, 64, 0.512980290285154286358e0),
  166. BOOST_MATH_BIG_CONSTANT(T, 64, -0.667758794592881019644e-1),
  167. BOOST_MATH_BIG_CONSTANT(T, 64, 0.131432469658444745835e-1),
  168. BOOST_MATH_BIG_CONSTANT(T, 64, -0.72303795326880286965e-3),
  169. BOOST_MATH_BIG_CONSTANT(T, 64, 0.447441185192951335042e-4),
  170. BOOST_MATH_BIG_CONSTANT(T, 64, -0.714539134024984593011e-6)
  171. };
  172. static const T d[] = {
  173. BOOST_MATH_BIG_CONSTANT(T, 64, 1.0),
  174. BOOST_MATH_BIG_CONSTANT(T, 64, -0.461477618025562520389e0),
  175. BOOST_MATH_BIG_CONSTANT(T, 64, 0.961237488025708540713e-1),
  176. BOOST_MATH_BIG_CONSTANT(T, 64, -0.116483957658204450739e-1),
  177. BOOST_MATH_BIG_CONSTANT(T, 64, 0.873308008461557544458e-3),
  178. BOOST_MATH_BIG_CONSTANT(T, 64, -0.387922804997682392562e-4),
  179. BOOST_MATH_BIG_CONSTANT(T, 64, 0.807473180049193557294e-6)
  180. };
  181. T result = x * Y + x * tools::evaluate_polynomial(n, x) / tools::evaluate_polynomial(d, x);
  182. return result;
  183. }
  184. template <class T, class P>
  185. T expm1_imp(T x, const std::integral_constant<int, 113>&, const P& pol)
  186. {
  187. BOOST_MATH_STD_USING
  188. T a = fabs(x);
  189. if(a > T(0.5L))
  190. {
  191. if(a >= tools::log_max_value<T>())
  192. {
  193. if(x > 0)
  194. return policies::raise_overflow_error<T>("boost::math::expm1<%1%>(%1%)", nullptr, pol);
  195. return -1;
  196. }
  197. return exp(x) - T(1);
  198. }
  199. if(a < tools::epsilon<T>())
  200. return x;
  201. static const float Y = 0.10281276702880859375e1f;
  202. static const T n[] = {
  203. BOOST_MATH_BIG_CONSTANT(T, 113, -0.28127670288085937499999999999999999854e-1),
  204. BOOST_MATH_BIG_CONSTANT(T, 113, 0.51278156911210477556524452177540792214e0),
  205. BOOST_MATH_BIG_CONSTANT(T, 113, -0.63263178520747096729500254678819588223e-1),
  206. BOOST_MATH_BIG_CONSTANT(T, 113, 0.14703285606874250425508446801230572252e-1),
  207. BOOST_MATH_BIG_CONSTANT(T, 113, -0.8675686051689527802425310407898459386e-3),
  208. BOOST_MATH_BIG_CONSTANT(T, 113, 0.88126359618291165384647080266133492399e-4),
  209. BOOST_MATH_BIG_CONSTANT(T, 113, -0.25963087867706310844432390015463138953e-5),
  210. BOOST_MATH_BIG_CONSTANT(T, 113, 0.14226691087800461778631773363204081194e-6),
  211. BOOST_MATH_BIG_CONSTANT(T, 113, -0.15995603306536496772374181066765665596e-8),
  212. BOOST_MATH_BIG_CONSTANT(T, 113, 0.45261820069007790520447958280473183582e-10)
  213. };
  214. static const T d[] = {
  215. BOOST_MATH_BIG_CONSTANT(T, 113, 1.0),
  216. BOOST_MATH_BIG_CONSTANT(T, 113, -0.45441264709074310514348137469214538853e0),
  217. BOOST_MATH_BIG_CONSTANT(T, 113, 0.96827131936192217313133611655555298106e-1),
  218. BOOST_MATH_BIG_CONSTANT(T, 113, -0.12745248725908178612540554584374876219e-1),
  219. BOOST_MATH_BIG_CONSTANT(T, 113, 0.11473613871583259821612766907781095472e-2),
  220. BOOST_MATH_BIG_CONSTANT(T, 113, -0.73704168477258911962046591907690764416e-4),
  221. BOOST_MATH_BIG_CONSTANT(T, 113, 0.34087499397791555759285503797256103259e-5),
  222. BOOST_MATH_BIG_CONSTANT(T, 113, -0.11114024704296196166272091230695179724e-6),
  223. BOOST_MATH_BIG_CONSTANT(T, 113, 0.23987051614110848595909588343223896577e-8),
  224. BOOST_MATH_BIG_CONSTANT(T, 113, -0.29477341859111589208776402638429026517e-10),
  225. BOOST_MATH_BIG_CONSTANT(T, 113, 0.13222065991022301420255904060628100924e-12)
  226. };
  227. T result = x * Y + x * tools::evaluate_polynomial(n, x) / tools::evaluate_polynomial(d, x);
  228. return result;
  229. }
  230. } // namespace detail
  231. template <class T, class Policy>
  232. inline typename tools::promote_args<T>::type expm1(T x, const Policy& /* pol */)
  233. {
  234. typedef typename tools::promote_args<T>::type result_type;
  235. typedef typename policies::evaluation<result_type, Policy>::type value_type;
  236. typedef typename policies::precision<result_type, Policy>::type precision_type;
  237. typedef typename policies::normalise<
  238. Policy,
  239. policies::promote_float<false>,
  240. policies::promote_double<false>,
  241. policies::discrete_quantile<>,
  242. policies::assert_undefined<> >::type forwarding_policy;
  243. typedef std::integral_constant<int,
  244. precision_type::value <= 0 ? 0 :
  245. precision_type::value <= 53 ? 53 :
  246. precision_type::value <= 64 ? 64 :
  247. precision_type::value <= 113 ? 113 : 0
  248. > tag_type;
  249. detail::expm1_initializer<value_type, forwarding_policy, tag_type>::force_instantiate();
  250. return policies::checked_narrowing_cast<result_type, forwarding_policy>(detail::expm1_imp(
  251. static_cast<value_type>(x),
  252. tag_type(), forwarding_policy()), "boost::math::expm1<%1%>(%1%)");
  253. }
  254. #ifdef expm1
  255. # ifndef BOOST_HAS_expm1
  256. # define BOOST_HAS_expm1
  257. # endif
  258. # undef expm1
  259. #endif
  260. #if defined(BOOST_HAS_EXPM1) && !(defined(__osf__) && defined(__DECCXX_VER))
  261. # ifdef BOOST_MATH_USE_C99
  262. inline float expm1(float x, const policies::policy<>&){ return ::expm1f(x); }
  263. # ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
  264. inline long double expm1(long double x, const policies::policy<>&){ return ::expm1l(x); }
  265. # endif
  266. # else
  267. inline float expm1(float x, const policies::policy<>&){ return static_cast<float>(::expm1(x)); }
  268. # endif
  269. inline double expm1(double x, const policies::policy<>&){ return ::expm1(x); }
  270. #endif
  271. template <class T>
  272. inline typename tools::promote_args<T>::type expm1(T x)
  273. {
  274. return expm1(x, policies::policy<>());
  275. }
  276. } // namespace math
  277. } // namespace boost
  278. #endif // BOOST_MATH_HYPOT_INCLUDED