PageRenderTime 22ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/Src/Dependencies/Boost/boost/math/special_functions/log1p.hpp

http://hadesmem.googlecode.com/
C++ Header | 471 lines | 368 code | 50 blank | 53 comment | 51 complexity | e1fd72f704ca0c39c19d1726ff8a906e MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.0, Apache-2.0, LGPL-3.0
  1. // (C) Copyright John Maddock 2005-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_LOG1P_INCLUDED
  6. #define BOOST_MATH_LOG1P_INCLUDED
  7. #ifdef _MSC_VER
  8. #pragma once
  9. #endif
  10. #include <boost/config/no_tr1/cmath.hpp>
  11. #include <math.h> // platform's ::log1p
  12. #include <boost/limits.hpp>
  13. #include <boost/math/tools/config.hpp>
  14. #include <boost/math/tools/series.hpp>
  15. #include <boost/math/tools/rational.hpp>
  16. #include <boost/math/policies/error_handling.hpp>
  17. #include <boost/math/special_functions/math_fwd.hpp>
  18. #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
  19. # include <boost/static_assert.hpp>
  20. #else
  21. # include <boost/assert.hpp>
  22. #endif
  23. namespace boost{ namespace math{
  24. namespace detail
  25. {
  26. // Functor log1p_series returns the next term in the Taylor series
  27. // pow(-1, k-1)*pow(x, k) / k
  28. // each time that operator() is invoked.
  29. //
  30. template <class T>
  31. struct log1p_series
  32. {
  33. typedef T result_type;
  34. log1p_series(T x)
  35. : k(0), m_mult(-x), m_prod(-1){}
  36. T operator()()
  37. {
  38. m_prod *= m_mult;
  39. return m_prod / ++k;
  40. }
  41. int count()const
  42. {
  43. return k;
  44. }
  45. private:
  46. int k;
  47. const T m_mult;
  48. T m_prod;
  49. log1p_series(const log1p_series&);
  50. log1p_series& operator=(const log1p_series&);
  51. };
  52. // Algorithm log1p is part of C99, but is not yet provided by many compilers.
  53. //
  54. // This version uses a Taylor series expansion for 0.5 > x > epsilon, which may
  55. // require up to std::numeric_limits<T>::digits+1 terms to be calculated.
  56. // It would be much more efficient to use the equivalence:
  57. // log(1+x) == (log(1+x) * x) / ((1-x) - 1)
  58. // Unfortunately many optimizing compilers make such a mess of this, that
  59. // it performs no better than log(1+x): which is to say not very well at all.
  60. //
  61. template <class T, class Policy>
  62. T log1p_imp(T const & x, const Policy& pol, const mpl::int_<0>&)
  63. { // The function returns the natural logarithm of 1 + x.
  64. typedef typename tools::promote_args<T>::type result_type;
  65. BOOST_MATH_STD_USING
  66. static const char* function = "boost::math::log1p<%1%>(%1%)";
  67. if(x < -1)
  68. return policies::raise_domain_error<T>(
  69. function, "log1p(x) requires x > -1, but got x = %1%.", x, pol);
  70. if(x == -1)
  71. return -policies::raise_overflow_error<T>(
  72. function, 0, pol);
  73. result_type a = abs(result_type(x));
  74. if(a > result_type(0.5f))
  75. return log(1 + result_type(x));
  76. // Note that without numeric_limits specialisation support,
  77. // epsilon just returns zero, and our "optimisation" will always fail:
  78. if(a < tools::epsilon<result_type>())
  79. return x;
  80. detail::log1p_series<result_type> s(x);
  81. boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
  82. #if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) && !BOOST_WORKAROUND(__EDG_VERSION__, <= 245)
  83. result_type result = tools::sum_series(s, policies::get_epsilon<result_type, Policy>(), max_iter);
  84. #else
  85. result_type zero = 0;
  86. result_type result = tools::sum_series(s, policies::get_epsilon<result_type, Policy>(), max_iter, zero);
  87. #endif
  88. policies::check_series_iterations(function, max_iter, pol);
  89. return result;
  90. }
  91. template <class T, class Policy>
  92. T log1p_imp(T const& x, const Policy& pol, const mpl::int_<53>&)
  93. { // The function returns the natural logarithm of 1 + x.
  94. BOOST_MATH_STD_USING
  95. static const char* function = "boost::math::log1p<%1%>(%1%)";
  96. if(x < -1)
  97. return policies::raise_domain_error<T>(
  98. function, "log1p(x) requires x > -1, but got x = %1%.", x, pol);
  99. if(x == -1)
  100. return -policies::raise_overflow_error<T>(
  101. function, 0, pol);
  102. T a = fabs(x);
  103. if(a > 0.5f)
  104. return log(1 + x);
  105. // Note that without numeric_limits specialisation support,
  106. // epsilon just returns zero, and our "optimisation" will always fail:
  107. if(a < tools::epsilon<T>())
  108. return x;
  109. // Maximum Deviation Found: 1.846e-017
  110. // Expected Error Term: 1.843e-017
  111. // Maximum Relative Change in Control Points: 8.138e-004
  112. // Max Error found at double precision = 3.250766e-016
  113. static const T P[] = {
  114. 0.15141069795941984e-16L,
  115. 0.35495104378055055e-15L,
  116. 0.33333333333332835L,
  117. 0.99249063543365859L,
  118. 1.1143969784156509L,
  119. 0.58052937949269651L,
  120. 0.13703234928513215L,
  121. 0.011294864812099712L
  122. };
  123. static const T Q[] = {
  124. 1L,
  125. 3.7274719063011499L,
  126. 5.5387948649720334L,
  127. 4.159201143419005L,
  128. 1.6423855110312755L,
  129. 0.31706251443180914L,
  130. 0.022665554431410243L,
  131. -0.29252538135177773e-5L
  132. };
  133. T result = 1 - x / 2 + tools::evaluate_polynomial(P, x) / tools::evaluate_polynomial(Q, x);
  134. result *= x;
  135. return result;
  136. }
  137. template <class T, class Policy>
  138. T log1p_imp(T const& x, const Policy& pol, const mpl::int_<64>&)
  139. { // The function returns the natural logarithm of 1 + x.
  140. BOOST_MATH_STD_USING
  141. static const char* function = "boost::math::log1p<%1%>(%1%)";
  142. if(x < -1)
  143. return policies::raise_domain_error<T>(
  144. function, "log1p(x) requires x > -1, but got x = %1%.", x, pol);
  145. if(x == -1)
  146. return -policies::raise_overflow_error<T>(
  147. function, 0, pol);
  148. T a = fabs(x);
  149. if(a > 0.5f)
  150. return log(1 + x);
  151. // Note that without numeric_limits specialisation support,
  152. // epsilon just returns zero, and our "optimisation" will always fail:
  153. if(a < tools::epsilon<T>())
  154. return x;
  155. // Maximum Deviation Found: 8.089e-20
  156. // Expected Error Term: 8.088e-20
  157. // Maximum Relative Change in Control Points: 9.648e-05
  158. // Max Error found at long double precision = 2.242324e-19
  159. static const T P[] = {
  160. -0.807533446680736736712e-19L,
  161. -0.490881544804798926426e-18L,
  162. 0.333333333333333373941L,
  163. 1.17141290782087994162L,
  164. 1.62790522814926264694L,
  165. 1.13156411870766876113L,
  166. 0.408087379932853785336L,
  167. 0.0706537026422828914622L,
  168. 0.00441709903782239229447L
  169. };
  170. static const T Q[] = {
  171. 1L,
  172. 4.26423872346263928361L,
  173. 7.48189472704477708962L,
  174. 6.94757016732904280913L,
  175. 3.6493508622280767304L,
  176. 1.06884863623790638317L,
  177. 0.158292216998514145947L,
  178. 0.00885295524069924328658L,
  179. -0.560026216133415663808e-6L
  180. };
  181. T result = 1 - x / 2 + tools::evaluate_polynomial(P, x) / tools::evaluate_polynomial(Q, x);
  182. result *= x;
  183. return result;
  184. }
  185. template <class T, class Policy>
  186. T log1p_imp(T const& x, const Policy& pol, const mpl::int_<24>&)
  187. { // The function returns the natural logarithm of 1 + x.
  188. BOOST_MATH_STD_USING
  189. static const char* function = "boost::math::log1p<%1%>(%1%)";
  190. if(x < -1)
  191. return policies::raise_domain_error<T>(
  192. function, "log1p(x) requires x > -1, but got x = %1%.", x, pol);
  193. if(x == -1)
  194. return -policies::raise_overflow_error<T>(
  195. function, 0, pol);
  196. T a = fabs(x);
  197. if(a > 0.5f)
  198. return log(1 + x);
  199. // Note that without numeric_limits specialisation support,
  200. // epsilon just returns zero, and our "optimisation" will always fail:
  201. if(a < tools::epsilon<T>())
  202. return x;
  203. // Maximum Deviation Found: 6.910e-08
  204. // Expected Error Term: 6.910e-08
  205. // Maximum Relative Change in Control Points: 2.509e-04
  206. // Max Error found at double precision = 6.910422e-08
  207. // Max Error found at float precision = 8.357242e-08
  208. static const T P[] = {
  209. -0.671192866803148236519e-7L,
  210. 0.119670999140731844725e-6L,
  211. 0.333339469182083148598L,
  212. 0.237827183019664122066L
  213. };
  214. static const T Q[] = {
  215. 1L,
  216. 1.46348272586988539733L,
  217. 0.497859871350117338894L,
  218. -0.00471666268910169651936L
  219. };
  220. T result = 1 - x / 2 + tools::evaluate_polynomial(P, x) / tools::evaluate_polynomial(Q, x);
  221. result *= x;
  222. return result;
  223. }
  224. } // namespace detail
  225. template <class T, class Policy>
  226. inline typename tools::promote_args<T>::type log1p(T x, const Policy&)
  227. {
  228. typedef typename tools::promote_args<T>::type result_type;
  229. typedef typename policies::evaluation<result_type, Policy>::type value_type;
  230. typedef typename policies::precision<result_type, Policy>::type precision_type;
  231. typedef typename policies::normalise<
  232. Policy,
  233. policies::promote_float<false>,
  234. policies::promote_double<false>,
  235. policies::discrete_quantile<>,
  236. policies::assert_undefined<> >::type forwarding_policy;
  237. typedef typename mpl::if_<
  238. mpl::less_equal<precision_type, mpl::int_<0> >,
  239. mpl::int_<0>,
  240. typename mpl::if_<
  241. mpl::less_equal<precision_type, mpl::int_<53> >,
  242. mpl::int_<53>, // double
  243. typename mpl::if_<
  244. mpl::less_equal<precision_type, mpl::int_<64> >,
  245. mpl::int_<64>, // 80-bit long double
  246. mpl::int_<0> // too many bits, use generic version.
  247. >::type
  248. >::type
  249. >::type tag_type;
  250. return policies::checked_narrowing_cast<result_type, forwarding_policy>(
  251. detail::log1p_imp(static_cast<value_type>(x), forwarding_policy(), tag_type()), "boost::math::log1p<%1%>(%1%)");
  252. }
  253. #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
  254. // These overloads work around a type deduction bug:
  255. inline float log1p(float z)
  256. {
  257. return log1p<float>(z);
  258. }
  259. inline double log1p(double z)
  260. {
  261. return log1p<double>(z);
  262. }
  263. #ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
  264. inline long double log1p(long double z)
  265. {
  266. return log1p<long double>(z);
  267. }
  268. #endif
  269. #endif
  270. #ifdef log1p
  271. # ifndef BOOST_HAS_LOG1P
  272. # define BOOST_HAS_LOG1P
  273. # endif
  274. # undef log1p
  275. #endif
  276. #if defined(BOOST_HAS_LOG1P) && !(defined(__osf__) && defined(__DECCXX_VER))
  277. # ifdef BOOST_MATH_USE_C99
  278. template <class Policy>
  279. inline float log1p(float x, const Policy& pol)
  280. {
  281. if(x < -1)
  282. return policies::raise_domain_error<float>(
  283. "log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol);
  284. if(x == -1)
  285. return -policies::raise_overflow_error<float>(
  286. "log1p<%1%>(%1%)", 0, pol);
  287. return ::log1pf(x);
  288. }
  289. #ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
  290. template <class Policy>
  291. inline long double log1p(long double x, const Policy& pol)
  292. {
  293. if(x < -1)
  294. return policies::raise_domain_error<long double>(
  295. "log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol);
  296. if(x == -1)
  297. return -policies::raise_overflow_error<long double>(
  298. "log1p<%1%>(%1%)", 0, pol);
  299. return ::log1pl(x);
  300. }
  301. #endif
  302. #else
  303. template <class Policy>
  304. inline float log1p(float x, const Policy& pol)
  305. {
  306. if(x < -1)
  307. return policies::raise_domain_error<float>(
  308. "log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol);
  309. if(x == -1)
  310. return -policies::raise_overflow_error<float>(
  311. "log1p<%1%>(%1%)", 0, pol);
  312. return ::log1p(x);
  313. }
  314. #endif
  315. template <class Policy>
  316. inline double log1p(double x, const Policy& pol)
  317. {
  318. if(x < -1)
  319. return policies::raise_domain_error<double>(
  320. "log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol);
  321. if(x == -1)
  322. return -policies::raise_overflow_error<double>(
  323. "log1p<%1%>(%1%)", 0, pol);
  324. return ::log1p(x);
  325. }
  326. #elif defined(_MSC_VER) && (BOOST_MSVC >= 1400)
  327. //
  328. // You should only enable this branch if you are absolutely sure
  329. // that your compilers optimizer won't mess this code up!!
  330. // Currently tested with VC8 and Intel 9.1.
  331. //
  332. template <class Policy>
  333. inline double log1p(double x, const Policy& pol)
  334. {
  335. if(x < -1)
  336. return policies::raise_domain_error<double>(
  337. "log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol);
  338. if(x == -1)
  339. return -policies::raise_overflow_error<double>(
  340. "log1p<%1%>(%1%)", 0, pol);
  341. double u = 1+x;
  342. if(u == 1.0)
  343. return x;
  344. else
  345. return ::log(u)*(x/(u-1.0));
  346. }
  347. template <class Policy>
  348. inline float log1p(float x, const Policy& pol)
  349. {
  350. return static_cast<float>(boost::math::log1p(static_cast<double>(x), pol));
  351. }
  352. #ifndef _WIN32_WCE
  353. //
  354. // For some reason this fails to compile under WinCE...
  355. // Needs more investigation.
  356. //
  357. template <class Policy>
  358. inline long double log1p(long double x, const Policy& pol)
  359. {
  360. if(x < -1)
  361. return policies::raise_domain_error<long double>(
  362. "log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol);
  363. if(x == -1)
  364. return -policies::raise_overflow_error<long double>(
  365. "log1p<%1%>(%1%)", 0, pol);
  366. long double u = 1+x;
  367. if(u == 1.0)
  368. return x;
  369. else
  370. return ::logl(u)*(x/(u-1.0));
  371. }
  372. #endif
  373. #endif
  374. template <class T>
  375. inline typename tools::promote_args<T>::type log1p(T x)
  376. {
  377. return boost::math::log1p(x, policies::policy<>());
  378. }
  379. //
  380. // Compute log(1+x)-x:
  381. //
  382. template <class T, class Policy>
  383. inline typename tools::promote_args<T>::type
  384. log1pmx(T x, const Policy& pol)
  385. {
  386. typedef typename tools::promote_args<T>::type result_type;
  387. BOOST_MATH_STD_USING
  388. static const char* function = "boost::math::log1pmx<%1%>(%1%)";
  389. if(x < -1)
  390. return policies::raise_domain_error<T>(
  391. function, "log1pmx(x) requires x > -1, but got x = %1%.", x, pol);
  392. if(x == -1)
  393. return -policies::raise_overflow_error<T>(
  394. function, 0, pol);
  395. result_type a = abs(result_type(x));
  396. if(a > result_type(0.95f))
  397. return log(1 + result_type(x)) - result_type(x);
  398. // Note that without numeric_limits specialisation support,
  399. // epsilon just returns zero, and our "optimisation" will always fail:
  400. if(a < tools::epsilon<result_type>())
  401. return -x * x / 2;
  402. boost::math::detail::log1p_series<T> s(x);
  403. s();
  404. boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
  405. #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
  406. T zero = 0;
  407. T result = boost::math::tools::sum_series(s, policies::get_epsilon<T, Policy>(), max_iter, zero);
  408. #else
  409. T result = boost::math::tools::sum_series(s, policies::get_epsilon<T, Policy>(), max_iter);
  410. #endif
  411. policies::check_series_iterations(function, max_iter, pol);
  412. return result;
  413. }
  414. template <class T>
  415. inline typename tools::promote_args<T>::type log1pmx(T x)
  416. {
  417. return log1pmx(x, policies::policy<>());
  418. }
  419. } // namespace math
  420. } // namespace boost
  421. #endif // BOOST_MATH_LOG1P_INCLUDED