annotate DEPENDENCIES/generic/include/boost/math/special_functions/factorials.hpp @ 133:4acb5d8d80b6 tip

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