]> git.donarmstrong.com Git - rsem.git/blob - boost/math/special_functions/factorials.hpp
Updated boost to v1.55.0
[rsem.git] / boost / math / special_functions / factorials.hpp
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/gamma.hpp>
14 #include <boost/math/special_functions/math_fwd.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    //
145    // We don't optimise this for small n, because
146    // tgamma_delta_ratio is alreay optimised for that
147    // use case:
148    //
149    return 1 / boost::math::tgamma_delta_ratio(x, static_cast<T>(n), pol);
150 }
151
152 template <class T, class Policy>
153 inline T falling_factorial_imp(T x, unsigned n, const Policy& pol)
154 {
155    BOOST_STATIC_ASSERT(!boost::is_integral<T>::value);
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 < n-1)
170    {
171       //
172       // x+1-n will be negative and tgamma_delta_ratio won't
173       // handle it, split the product up into three parts:
174       //
175       T xp1 = x + 1;
176       unsigned n2 = itrunc((T)floor(xp1), pol);
177       if(n2 == xp1)
178          return 0;
179       T result = boost::math::tgamma_delta_ratio(xp1, -static_cast<T>(n2), pol);
180       x -= n2;
181       result *= x;
182       ++n2;
183       if(n2 < n)
184          result *= falling_factorial(x - 1, n - n2, pol);
185       return result;
186    }
187    //
188    // Simple case: just the ratio of two
189    // (positive argument) gamma functions.
190    // Note that we don't optimise this for small n,
191    // because tgamma_delta_ratio is alreay optimised
192    // for that use case:
193    //
194    return boost::math::tgamma_delta_ratio(x + 1, -static_cast<T>(n), pol);
195 }
196
197 } // namespace detail
198
199 template <class RT>
200 inline typename tools::promote_args<RT>::type
201    falling_factorial(RT x, unsigned n)
202 {
203    typedef typename tools::promote_args<RT>::type result_type;
204    return detail::falling_factorial_imp(
205       static_cast<result_type>(x), n, policies::policy<>());
206 }
207
208 template <class RT, class Policy>
209 inline typename tools::promote_args<RT>::type
210    falling_factorial(RT x, unsigned n, const Policy& pol)
211 {
212    typedef typename tools::promote_args<RT>::type result_type;
213    return detail::falling_factorial_imp(
214       static_cast<result_type>(x), n, pol);
215 }
216
217 template <class RT>
218 inline typename tools::promote_args<RT>::type
219    rising_factorial(RT x, int n)
220 {
221    typedef typename tools::promote_args<RT>::type result_type;
222    return detail::rising_factorial_imp(
223       static_cast<result_type>(x), n, policies::policy<>());
224 }
225
226 template <class RT, class Policy>
227 inline typename tools::promote_args<RT>::type
228    rising_factorial(RT x, int n, const Policy& pol)
229 {
230    typedef typename tools::promote_args<RT>::type result_type;
231    return detail::rising_factorial_imp(
232       static_cast<result_type>(x), n, pol);
233 }
234
235 } // namespace math
236 } // namespace boost
237
238 #endif // BOOST_MATH_SP_FACTORIALS_HPP
239