factorials.hpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. // Copyright John Maddock 2006, 2010.
  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_SP_FACTORIALS_HPP
  6. #define BOOST_MATH_SP_FACTORIALS_HPP
  7. #ifdef _MSC_VER
  8. #pragma once
  9. #endif
  10. #include <boost/math/special_functions/math_fwd.hpp>
  11. #include <boost/math/special_functions/gamma.hpp>
  12. #include <boost/math/special_functions/detail/unchecked_factorial.hpp>
  13. #include <boost/array.hpp>
  14. #ifdef BOOST_MSVC
  15. #pragma warning(push) // Temporary until lexical cast fixed.
  16. #pragma warning(disable: 4127 4701)
  17. #endif
  18. #ifdef BOOST_MSVC
  19. #pragma warning(pop)
  20. #endif
  21. #include <boost/config/no_tr1/cmath.hpp>
  22. namespace boost { namespace math
  23. {
  24. template <class T, class Policy>
  25. inline T factorial(unsigned i, const Policy& pol)
  26. {
  27. BOOST_STATIC_ASSERT(!boost::is_integral<T>::value);
  28. // factorial<unsigned int>(n) is not implemented
  29. // because it would overflow integral type T for too small n
  30. // to be useful. Use instead a floating-point type,
  31. // and convert to an unsigned type if essential, for example:
  32. // unsigned int nfac = static_cast<unsigned int>(factorial<double>(n));
  33. // See factorial documentation for more detail.
  34. BOOST_MATH_STD_USING // Aid ADL for floor.
  35. if(i <= max_factorial<T>::value)
  36. return unchecked_factorial<T>(i);
  37. T result = boost::math::tgamma(static_cast<T>(i+1), pol);
  38. if(result > tools::max_value<T>())
  39. return result; // Overflowed value! (But tgamma will have signalled the error already).
  40. return floor(result + 0.5f);
  41. }
  42. template <class T>
  43. inline T factorial(unsigned i)
  44. {
  45. return factorial<T>(i, policies::policy<>());
  46. }
  47. /*
  48. // Can't have these in a policy enabled world?
  49. template<>
  50. inline float factorial<float>(unsigned i)
  51. {
  52. if(i <= max_factorial<float>::value)
  53. return unchecked_factorial<float>(i);
  54. return tools::overflow_error<float>(BOOST_CURRENT_FUNCTION);
  55. }
  56. template<>
  57. inline double factorial<double>(unsigned i)
  58. {
  59. if(i <= max_factorial<double>::value)
  60. return unchecked_factorial<double>(i);
  61. return tools::overflow_error<double>(BOOST_CURRENT_FUNCTION);
  62. }
  63. */
  64. template <class T, class Policy>
  65. T double_factorial(unsigned i, const Policy& pol)
  66. {
  67. BOOST_STATIC_ASSERT(!boost::is_integral<T>::value);
  68. BOOST_MATH_STD_USING // ADL lookup of std names
  69. if(i & 1)
  70. {
  71. // odd i:
  72. if(i < max_factorial<T>::value)
  73. {
  74. unsigned n = (i - 1) / 2;
  75. return ceil(unchecked_factorial<T>(i) / (ldexp(T(1), (int)n) * unchecked_factorial<T>(n)) - 0.5f);
  76. }
  77. //
  78. // Fallthrough: i is too large to use table lookup, try the
  79. // gamma function instead.
  80. //
  81. T result = boost::math::tgamma(static_cast<T>(i) / 2 + 1, pol) / sqrt(constants::pi<T>());
  82. if(ldexp(tools::max_value<T>(), -static_cast<int>(i+1) / 2) > result)
  83. return ceil(result * ldexp(T(1), static_cast<int>(i+1) / 2) - 0.5f);
  84. }
  85. else
  86. {
  87. // even i:
  88. unsigned n = i / 2;
  89. T result = factorial<T>(n, pol);
  90. if(ldexp(tools::max_value<T>(), -(int)n) > result)
  91. return result * ldexp(T(1), (int)n);
  92. }
  93. //
  94. // If we fall through to here then the result is infinite:
  95. //
  96. return policies::raise_overflow_error<T>("boost::math::double_factorial<%1%>(unsigned)", 0, pol);
  97. }
  98. template <class T>
  99. inline T double_factorial(unsigned i)
  100. {
  101. return double_factorial<T>(i, policies::policy<>());
  102. }
  103. namespace detail{
  104. template <class T, class Policy>
  105. T rising_factorial_imp(T x, int n, const Policy& pol)
  106. {
  107. BOOST_STATIC_ASSERT(!boost::is_integral<T>::value);
  108. if(x < 0)
  109. {
  110. //
  111. // For x less than zero, we really have a falling
  112. // factorial, modulo a possible change of sign.
  113. //
  114. // Note that the falling factorial isn't defined
  115. // for negative n, so we'll get rid of that case
  116. // first:
  117. //
  118. bool inv = false;
  119. if(n < 0)
  120. {
  121. x += n;
  122. n = -n;
  123. inv = true;
  124. }
  125. T result = ((n&1) ? -1 : 1) * falling_factorial(-x, n, pol);
  126. if(inv)
  127. result = 1 / result;
  128. return result;
  129. }
  130. if(n == 0)
  131. return 1;
  132. if(x == 0)
  133. {
  134. if(n < 0)
  135. return -boost::math::tgamma_delta_ratio(x + 1, static_cast<T>(-n), pol);
  136. else
  137. return 0;
  138. }
  139. if((x < 1) && (x + n < 0))
  140. {
  141. T val = boost::math::tgamma_delta_ratio(1 - x, static_cast<T>(-n), pol);
  142. return (n & 1) ? T(-val) : val;
  143. }
  144. //
  145. // We don't optimise this for small n, because
  146. // tgamma_delta_ratio is already optimised for that
  147. // use case:
  148. //
  149. return 1 / boost::math::tgamma_delta_ratio(x, static_cast<T>(n), pol);
  150. }
  151. template <class T, class Policy>
  152. inline T falling_factorial_imp(T x, unsigned n, const Policy& pol)
  153. {
  154. BOOST_STATIC_ASSERT(!boost::is_integral<T>::value);
  155. BOOST_MATH_STD_USING // ADL of std names
  156. if(x == 0)
  157. return 0;
  158. if(x < 0)
  159. {
  160. //
  161. // For x < 0 we really have a rising factorial
  162. // modulo a possible change of sign:
  163. //
  164. return (n&1 ? -1 : 1) * rising_factorial(-x, n, pol);
  165. }
  166. if(n == 0)
  167. return 1;
  168. if(x < 0.5f)
  169. {
  170. //
  171. // 1 + x below will throw away digits, so split up calculation:
  172. //
  173. if(n > max_factorial<T>::value - 2)
  174. {
  175. // If the two end of the range are far apart we have a ratio of two very large
  176. // numbers, split the calculation up into two blocks:
  177. T t1 = x * boost::math::falling_factorial(x - 1, max_factorial<T>::value - 2, pol);
  178. T t2 = boost::math::falling_factorial(x - max_factorial<T>::value + 1, n - max_factorial<T>::value + 1, pol);
  179. if(tools::max_value<T>() / fabs(t1) < fabs(t2))
  180. return boost::math::sign(t1) * boost::math::sign(t2) * policies::raise_overflow_error<T>("boost::math::falling_factorial<%1%>", 0, pol);
  181. return t1 * t2;
  182. }
  183. return x * boost::math::falling_factorial(x - 1, n - 1, pol);
  184. }
  185. if(x <= n - 1)
  186. {
  187. //
  188. // x+1-n will be negative and tgamma_delta_ratio won't
  189. // handle it, split the product up into three parts:
  190. //
  191. T xp1 = x + 1;
  192. unsigned n2 = itrunc((T)floor(xp1), pol);
  193. if(n2 == xp1)
  194. return 0;
  195. T result = boost::math::tgamma_delta_ratio(xp1, -static_cast<T>(n2), pol);
  196. x -= n2;
  197. result *= x;
  198. ++n2;
  199. if(n2 < n)
  200. result *= falling_factorial(x - 1, n - n2, pol);
  201. return result;
  202. }
  203. //
  204. // Simple case: just the ratio of two
  205. // (positive argument) gamma functions.
  206. // Note that we don't optimise this for small n,
  207. // because tgamma_delta_ratio is already optimised
  208. // for that use case:
  209. //
  210. return boost::math::tgamma_delta_ratio(x + 1, -static_cast<T>(n), pol);
  211. }
  212. } // namespace detail
  213. template <class RT>
  214. inline typename tools::promote_args<RT>::type
  215. falling_factorial(RT x, unsigned n)
  216. {
  217. typedef typename tools::promote_args<RT>::type result_type;
  218. return detail::falling_factorial_imp(
  219. static_cast<result_type>(x), n, policies::policy<>());
  220. }
  221. template <class RT, class Policy>
  222. inline typename tools::promote_args<RT>::type
  223. falling_factorial(RT x, unsigned n, const Policy& pol)
  224. {
  225. typedef typename tools::promote_args<RT>::type result_type;
  226. return detail::falling_factorial_imp(
  227. static_cast<result_type>(x), n, pol);
  228. }
  229. template <class RT>
  230. inline typename tools::promote_args<RT>::type
  231. rising_factorial(RT x, int n)
  232. {
  233. typedef typename tools::promote_args<RT>::type result_type;
  234. return detail::rising_factorial_imp(
  235. static_cast<result_type>(x), n, policies::policy<>());
  236. }
  237. template <class RT, class Policy>
  238. inline typename tools::promote_args<RT>::type
  239. rising_factorial(RT x, int n, const Policy& pol)
  240. {
  241. typedef typename tools::promote_args<RT>::type result_type;
  242. return detail::rising_factorial_imp(
  243. static_cast<result_type>(x), n, pol);
  244. }
  245. } // namespace math
  246. } // namespace boost
  247. #endif // BOOST_MATH_SP_FACTORIALS_HPP