diff options
Diffstat (limited to 'vendor/gmp-6.3.0/mpz/fac_ui.c')
-rw-r--r-- | vendor/gmp-6.3.0/mpz/fac_ui.c | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/vendor/gmp-6.3.0/mpz/fac_ui.c b/vendor/gmp-6.3.0/mpz/fac_ui.c new file mode 100644 index 0000000..a7998b3 --- /dev/null +++ b/vendor/gmp-6.3.0/mpz/fac_ui.c @@ -0,0 +1,122 @@ +/* mpz_fac_ui(RESULT, N) -- Set RESULT to N!. + +Contributed to the GNU project by Marco Bodrato. + +Copyright 1991, 1993-1995, 2000-2003, 2011, 2012, 2015, 2021 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 either: + + * 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. + +or + + * the GNU General Public License as published by the Free Software + Foundation; either version 2 of the License, or (at your option) any + later version. + +or both in parallel, as here. + +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 General Public License +for more details. + +You should have received copies of the GNU General Public License and the +GNU Lesser General Public License along with the GNU MP Library. If not, +see https://www.gnu.org/licenses/. */ + +#include "gmp-impl.h" + +#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) + +#if TUNE_PROGRAM_BUILD +#define FACTORS_PER_LIMB (GMP_NUMB_BITS / (LOG2C(FAC_DSC_THRESHOLD_LIMIT-1)+1)) +#else +#define FACTORS_PER_LIMB (GMP_NUMB_BITS / (LOG2C(FAC_ODD_THRESHOLD)+1)) +#endif + +/* Computes n!, the factorial of n. + WARNING: it assumes that n fits in a limb! + */ +void +mpz_fac_ui (mpz_ptr x, unsigned long n) +{ + static const mp_limb_t table[] = { ONE_LIMB_FACTORIAL_TABLE }; + + ASSERT (n <= GMP_NUMB_MAX); + + if (n < numberof (table)) + { + MPZ_NEWALLOC (x, 1)[0] = table[n]; + SIZ (x) = 1; + } + else if (BELOW_THRESHOLD (n, FAC_ODD_THRESHOLD)) + { + mp_limb_t prod, max_prod; + mp_size_t j; + mp_ptr factors; + mp_limb_t fac, diff = n - numberof (table); + TMP_SDECL; + + TMP_SMARK; + factors = TMP_SALLOC_LIMBS (2 + diff / FACTORS_PER_LIMB); + + factors[0] = table[numberof (table)-1]; + j = 1; + if ((diff & 1) == 0) + { + prod = n; + /* if (diff != 0) */ + fac = --n * numberof (table); + } + else + { + prod = n * numberof (table); + fac = prod + --diff; + } + +#if TUNE_PROGRAM_BUILD + max_prod = GMP_NUMB_MAX / (FAC_DSC_THRESHOLD_LIMIT * FAC_DSC_THRESHOLD_LIMIT); +#else + max_prod = GMP_NUMB_MAX / + (((FAC_ODD_THRESHOLD + numberof (table) + 1) / 2) * + ((FAC_ODD_THRESHOLD + numberof (table)) / 2)); +#endif + for (;diff != 0; fac += (diff -= 2)) + FACTOR_LIST_STORE (fac, prod, max_prod, factors, j); + + factors[j++] = prod; + mpz_prodlimbs (x, factors, j); + + TMP_SFREE; + } + else + { + mp_limb_t count; + mpz_oddfac_1 (x, n, 0); + if (n <= TABLE_LIMIT_2N_MINUS_POPC_2N) + count = __gmp_fac2cnt_table[n / 2 - 1]; + else + { + popc_limb (count, n); + count = n - count; + } + mpz_mul_2exp (x, x, count); + } +} + +#undef FACTORS_PER_LIMB +#undef FACTOR_LIST_STORE |