factorials.hpp 8.1 KB

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