inline T falling_factorial_imp(T x, unsigned n, const Policy& pol) { BOOST_STATIC_ASSERT(!boost::is_integral<T>::value); BOOST_MATH_STD_USING // ADL of std names if((x == 0) && (n >= 0)) return 0; if(x < 0) { // // For x < 0 we really have a rising factorial // modulo a possible change of sign: // return (n&1 ? -1 : 1) * rising_factorial(-x, n, pol); } if(n == 0) return 1; if(x < 0.5f) { // // 1 + x below will throw away digits, so split up calculation: // if(n > max_factorial<T>::value - 2) { // If the two end of the range are far apart we have a ratio of two very large // numbers, split the calculation up into two blocks: T t1 = x * boost::math::falling_factorial(x - 1, max_factorial<T>::value - 2); T t2 = boost::math::falling_factorial(x - max_factorial<T>::value + 1, n - max_factorial<T>::value + 1); if(tools::max_value<T>() / fabs(t1) < fabs(t2)) return boost::math::sign(t1) * boost::math::sign(t2) * policies::raise_overflow_error<T>("boost::math::falling_factorial<%1%>", 0, pol); return t1 * t2; } return x * boost::math::falling_factorial(x - 1, n - 1); } if(x <= n - 1) { // // x+1-n will be negative and tgamma_delta_ratio won't // handle it, split the product up into three parts: // T xp1 = x + 1; unsigned n2 = itrunc((T)floor(xp1), pol); if(n2 == xp1) return 0; T result = boost::math::tgamma_delta_ratio(xp1, -static_cast<T>(n2), pol); x -= n2; result *= x; ++n2; if(n2 < n) result *= falling_factorial(x - 1, n - n2, pol); return result; } // // Simple case: just the ratio of two // (positive argument) gamma functions. // Note that we don't optimise this for small n, // because tgamma_delta_ratio is alreay optimised // for that use case: // return boost::math::tgamma_delta_ratio(x + 1, -static_cast<T>(n), pol); }
T rising_factorial_imp(T x, int n, const Policy& pol) { BOOST_STATIC_ASSERT(!lslboost::is_integral<T>::value); if(x < 0) { // // For x less than zero, we really have a falling // factorial, modulo a possible change of sign. // // Note that the falling factorial isn't defined // for negative n, so we'll get rid of that case // first: // bool inv = false; if(n < 0) { x += n; n = -n; inv = true; } T result = ((n&1) ? -1 : 1) * falling_factorial(-x, n, pol); if(inv) result = 1 / result; return result; } if(n == 0) return 1; // // We don't optimise this for small n, because // tgamma_delta_ratio is alreay optimised for that // use case: // return 1 / lslboost::math::tgamma_delta_ratio(x, static_cast<T>(n), pol); }
inline T falling_factorial_imp(T x, unsigned n, const Policy& pol) { BOOST_STATIC_ASSERT(!lslboost::is_integral<T>::value); BOOST_MATH_STD_USING // ADL of std names if(x == 0) return 0; if(x < 0) { // // For x < 0 we really have a rising factorial // modulo a possible change of sign: // return (n&1 ? -1 : 1) * rising_factorial(-x, n, pol); } if(n == 0) return 1; if(x < n-1) { // // x+1-n will be negative and tgamma_delta_ratio won't // handle it, split the product up into three parts: // T xp1 = x + 1; unsigned n2 = itrunc((T)floor(xp1), pol); if(n2 == xp1) return 0; T result = lslboost::math::tgamma_delta_ratio(xp1, -static_cast<T>(n2), pol); x -= n2; result *= x; ++n2; if(n2 < n) result *= falling_factorial(x - 1, n - n2, pol); return result; } // // Simple case: just the ratio of two // (positive argument) gamma functions. // Note that we don't optimise this for small n, // because tgamma_delta_ratio is alreay optimised // for that use case: // return lslboost::math::tgamma_delta_ratio(x + 1, -static_cast<T>(n), pol); }
int test_main(int, char* []) { int i; TEST_POLICY_SF(tgamma(3.0)); TEST_POLICY_SF(tgamma1pm1(0.25)); TEST_POLICY_SF(lgamma(50.0)); TEST_POLICY_SF(lgamma(50.0, &i)); TEST_POLICY_SF(digamma(12.0)); TEST_POLICY_SF(tgamma_ratio(12.0, 13.5)); TEST_POLICY_SF(tgamma_delta_ratio(100.0, 0.25)); TEST_POLICY_SF(factorial<double>(8)); TEST_POLICY_SF(unchecked_factorial<double>(3)); TEST_POLICY_SF(double_factorial<double>(5)); TEST_POLICY_SF(rising_factorial(20.5, 5)); TEST_POLICY_SF(falling_factorial(10.2, 7)); TEST_POLICY_SF(tgamma(12.0, 13.0)); TEST_POLICY_SF(tgamma_lower(12.0, 13.0)); TEST_POLICY_SF(gamma_p(12.0, 13.0)); TEST_POLICY_SF(gamma_q(12.0, 15.0)); TEST_POLICY_SF(gamma_p_inv(12.0, 0.25)); TEST_POLICY_SF(gamma_q_inv(15.0, 0.25)); TEST_POLICY_SF(gamma_p_inva(12.0, 0.25)); TEST_POLICY_SF(gamma_q_inva(12.0, 0.25)); TEST_POLICY_SF(erf(2.5)); TEST_POLICY_SF(erfc(2.5)); TEST_POLICY_SF(erf_inv(0.25)); TEST_POLICY_SF(erfc_inv(0.25)); TEST_POLICY_SF(beta(12.0, 15.0)); TEST_POLICY_SF(beta(12.0, 15.0, 0.25)); TEST_POLICY_SF(betac(12.0, 15.0, 0.25)); TEST_POLICY_SF(ibeta(12.0, 15.0, 0.25)); TEST_POLICY_SF(ibetac(12.0, 15.0, 0.25)); TEST_POLICY_SF(ibeta_inv(12.0, 15.0, 0.25)); TEST_POLICY_SF(ibetac_inv(12.0, 15.0, 0.25)); TEST_POLICY_SF(ibeta_inva(12.0, 0.75, 0.25)); TEST_POLICY_SF(ibetac_inva(12.0, 0.75, 0.25)); TEST_POLICY_SF(ibeta_invb(12.0, 0.75, 0.25)); TEST_POLICY_SF(ibetac_invb(12.0, 0.75, 0.25)); TEST_POLICY_SF(gamma_p_derivative(12.0, 15.0)); TEST_POLICY_SF(ibeta_derivative(12.0, 15.75, 0.25)); TEST_POLICY_SF(fpclassify(12.0)); TEST_POLICY_SF(isfinite(12.0)); TEST_POLICY_SF(isnormal(12.0)); TEST_POLICY_SF(isnan(12.0)); TEST_POLICY_SF(isinf(12.0)); TEST_POLICY_SF(log1p(0.0025)); TEST_POLICY_SF(expm1(0.0025)); TEST_POLICY_SF(cbrt(30.0)); TEST_POLICY_SF(sqrt1pm1(0.0025)); TEST_POLICY_SF(powm1(1.0025, 12.0)); TEST_POLICY_SF(legendre_p(5, 0.75)); TEST_POLICY_SF(legendre_p(7, 3, 0.75)); TEST_POLICY_SF(legendre_q(5, 0.75)); TEST_POLICY_SF(legendre_next(2, 0.25, 12.0, 5.0)); TEST_POLICY_SF(legendre_next(2, 2, 0.25, 12.0, 5.0)); TEST_POLICY_SF(laguerre(5, 12.2)); TEST_POLICY_SF(laguerre(7, 3, 5.0)); TEST_POLICY_SF(laguerre_next(2, 5.0, 12.0, 5.0)); TEST_POLICY_SF(laguerre_next(5, 3, 5.0, 20.0, 10.0)); TEST_POLICY_SF(hermite(1, 2.0)); TEST_POLICY_SF(hermite_next(2, 2.0, 3.0, 2.0)); TEST_POLICY_SF(spherical_harmonic_r(5, 4, 0.75, 0.25)); TEST_POLICY_SF(spherical_harmonic_i(5, 4, 0.75, 0.25)); TEST_POLICY_SF(ellint_1(0.25)); TEST_POLICY_SF(ellint_1(0.25, 0.75)); TEST_POLICY_SF(ellint_2(0.25)); TEST_POLICY_SF(ellint_2(0.25, 0.75)); TEST_POLICY_SF(ellint_3(0.25, 0.75)); TEST_POLICY_SF(ellint_3(0.25, 0.125, 0.75)); TEST_POLICY_SF(ellint_rc(3.0, 5.0)); TEST_POLICY_SF(ellint_rd(2.0, 3.0, 4.0)); TEST_POLICY_SF(ellint_rf(2.0, 3.0, 4.0)); TEST_POLICY_SF(ellint_rj(2.0, 3.0, 5.0, 0.25)); TEST_POLICY_SF(hypot(5.0, 3.0)); TEST_POLICY_SF(sinc_pi(3.0)); TEST_POLICY_SF(sinhc_pi(2.0)); TEST_POLICY_SF(asinh(12.0)); TEST_POLICY_SF(acosh(5.0)); TEST_POLICY_SF(atanh(0.75)); TEST_POLICY_SF(sin_pi(5.0)); TEST_POLICY_SF(cos_pi(6.0)); TEST_POLICY_SF(cyl_neumann(2.0, 5.0)); TEST_POLICY_SF(cyl_neumann(2, 5.0)); TEST_POLICY_SF(cyl_bessel_j(2.0, 5.0)); TEST_POLICY_SF(cyl_bessel_j(2, 5.0)); TEST_POLICY_SF(cyl_bessel_i(3.0, 5.0)); TEST_POLICY_SF(cyl_bessel_i(3, 5.0)); TEST_POLICY_SF(cyl_bessel_k(3.0, 5.0)); TEST_POLICY_SF(cyl_bessel_k(3, 5.0)); TEST_POLICY_SF(sph_bessel(3, 5.0)); TEST_POLICY_SF(sph_bessel(3, 5)); TEST_POLICY_SF(sph_neumann(3, 5.0)); TEST_POLICY_SF(sph_neumann(3, 5)); return 0; }
inline typename stan::return_type<T0,T1>::type operator()(const T0& arg1, const T1& arg2) const { return falling_factorial(arg1,arg2); }