/* mpz_mfac_uiui(RESULT, N, M) -- Set RESULT to N!^(M) = N(N-M)(N-2M)... Contributed to the GNU project by Marco Bodrato. Copyright 2012 Free Software Foundation, Inc. This file is part of the GNU MP Library. The GNU MP Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. The GNU MP Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */ #include "gmp.h" #include "gmp-impl.h" /*************************************************************/ /* Section macros: common macros, for swing/fac/bin (&sieve) */ /*************************************************************/ #define FACTOR_LIST_STORE(P, PR, MAX_PR, VEC, I) \ do { \ if ((PR) > (MAX_PR)) { \ (VEC)[(I)++] = (PR); \ (PR) = (P); \ } else \ (PR) *= (P); \ } while (0) /*********************************************************/ /* Section oder factorials: */ /*********************************************************/ /* mpz_mfac_uiui (x, n, m) computes x = n!^(m) = n*(n-m)*(n-2m)*... */ void mpz_mfac_uiui (mpz_ptr x, unsigned long n, unsigned long m) { ASSERT (n <= GMP_NUMB_MAX); ASSERT (m != 0); if (n < 3 || n - 3 < m - 1) { /* (n < 3 || n - 1 <= m || m == 0) */ PTR (x)[0] = n + (n == 0); SIZ (x) = 1; } else { /* m < n - 1 < GMP_NUMB_MAX */ mp_limb_t g, sn; mpz_t t; sn = n; g = mpn_gcd_1 (&sn, 1, m); if (g != 1) { n/=g; m/=g; } if (m <= 2) { /* fac or 2fac */ if (m == 1) { if (g > 2) { mpz_init (t); mpz_fac_ui (t, n); sn = n; } else { if (g == 2) mpz_2fac_ui (x, n << 1); else mpz_fac_ui (x, n); return; } } else { /* m == 2 */ if (g != 1) { mpz_init (t); mpz_2fac_ui (t, n); sn = n / 2 + 1; } else { mpz_2fac_ui (x, n); return; } } } else { /* m >= 3, gcd(n,m) = 1 */ mp_limb_t *factors; mp_limb_t prod, max_prod, j; TMP_DECL; sn = n / m + 1; j = 0; prod = n; n -= m; max_prod = GMP_NUMB_MAX / n; TMP_MARK; factors = TMP_ALLOC_LIMBS (sn / log_n_max (n) + 2); for (; n > m; n -= m) FACTOR_LIST_STORE (n, prod, max_prod, factors, j); factors[j++] = n; factors[j++] = prod; if (g > 1) { mpz_init (t); mpz_prodlimbs (t, factors, j); } else mpz_prodlimbs (x, factors, j); TMP_FREE; } if (g > 1) { mpz_t p; mpz_init (p); mpz_ui_pow_ui (p, g, sn); /* g^sn */ mpz_mul (x, p, t); mpz_clear (p); mpz_clear (t); } } }