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