186d7f5d3SJohn Marino /* mpz_fac_ui(result, n) -- Set RESULT to N!.
286d7f5d3SJohn Marino
386d7f5d3SJohn Marino Copyright 1991, 1993, 1994, 1995, 2000, 2001, 2002, 2003 Free Software
486d7f5d3SJohn Marino Foundation, Inc.
586d7f5d3SJohn Marino
686d7f5d3SJohn Marino This file is part of the GNU MP Library.
786d7f5d3SJohn Marino
886d7f5d3SJohn Marino The GNU MP Library is free software; you can redistribute it and/or modify
986d7f5d3SJohn Marino it under the terms of the GNU Lesser General Public License as published by
1086d7f5d3SJohn Marino the Free Software Foundation; either version 3 of the License, or (at your
1186d7f5d3SJohn Marino option) any later version.
1286d7f5d3SJohn Marino
1386d7f5d3SJohn Marino The GNU MP Library is distributed in the hope that it will be useful, but
1486d7f5d3SJohn Marino WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
1586d7f5d3SJohn Marino or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
1686d7f5d3SJohn Marino License for more details.
1786d7f5d3SJohn Marino
1886d7f5d3SJohn Marino You should have received a copy of the GNU Lesser General Public License
1986d7f5d3SJohn Marino along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */
2086d7f5d3SJohn Marino
2186d7f5d3SJohn Marino #include "gmp.h"
2286d7f5d3SJohn Marino #include "gmp-impl.h"
2386d7f5d3SJohn Marino #include "longlong.h"
2486d7f5d3SJohn Marino
2586d7f5d3SJohn Marino #include "fac_ui.h"
2686d7f5d3SJohn Marino
2786d7f5d3SJohn Marino
2886d7f5d3SJohn Marino static void odd_product __GMP_PROTO ((unsigned long, unsigned long, mpz_t *));
2986d7f5d3SJohn Marino static void ap_product_small __GMP_PROTO ((mpz_t, mp_limb_t, mp_limb_t, unsigned long, unsigned long));
3086d7f5d3SJohn Marino
3186d7f5d3SJohn Marino
3286d7f5d3SJohn Marino /* must be >=2 */
3386d7f5d3SJohn Marino #define APCONST 5
3486d7f5d3SJohn Marino
3586d7f5d3SJohn Marino /* for single non-zero limb */
3686d7f5d3SJohn Marino #define MPZ_SET_1_NZ(z,n) \
3786d7f5d3SJohn Marino do { \
3886d7f5d3SJohn Marino mpz_ptr __z = (z); \
3986d7f5d3SJohn Marino ASSERT ((n) != 0); \
4086d7f5d3SJohn Marino PTR(__z)[0] = (n); \
4186d7f5d3SJohn Marino SIZ(__z) = 1; \
4286d7f5d3SJohn Marino } while (0)
4386d7f5d3SJohn Marino
4486d7f5d3SJohn Marino /* for src>0 and n>0 */
4586d7f5d3SJohn Marino #define MPZ_MUL_1_POS(dst,src,n) \
4686d7f5d3SJohn Marino do { \
4786d7f5d3SJohn Marino mpz_ptr __dst = (dst); \
4886d7f5d3SJohn Marino mpz_srcptr __src = (src); \
4986d7f5d3SJohn Marino mp_size_t __size = SIZ(__src); \
5086d7f5d3SJohn Marino mp_ptr __dst_p; \
5186d7f5d3SJohn Marino mp_limb_t __c; \
5286d7f5d3SJohn Marino \
5386d7f5d3SJohn Marino ASSERT (__size > 0); \
5486d7f5d3SJohn Marino ASSERT ((n) != 0); \
5586d7f5d3SJohn Marino \
5686d7f5d3SJohn Marino MPZ_REALLOC (__dst, __size+1); \
5786d7f5d3SJohn Marino __dst_p = PTR(__dst); \
5886d7f5d3SJohn Marino \
5986d7f5d3SJohn Marino __c = mpn_mul_1 (__dst_p, PTR(__src), __size, n); \
6086d7f5d3SJohn Marino __dst_p[__size] = __c; \
6186d7f5d3SJohn Marino SIZ(__dst) = __size + (__c != 0); \
6286d7f5d3SJohn Marino } while (0)
6386d7f5d3SJohn Marino
6486d7f5d3SJohn Marino
6586d7f5d3SJohn Marino #if BITS_PER_ULONG == GMP_LIMB_BITS
6686d7f5d3SJohn Marino #define BSWAP_ULONG(x,y) BSWAP_LIMB(x,y)
6786d7f5d3SJohn Marino #endif
6886d7f5d3SJohn Marino
6986d7f5d3SJohn Marino /* We used to have a case here for limb==2*long, doing a BSWAP_LIMB followed
7086d7f5d3SJohn Marino by a shift down to get the high part. But it provoked incorrect code
7186d7f5d3SJohn Marino from "HP aC++/ANSI C B3910B A.05.52 [Sep 05 2003]" in ILP32 mode. This
7286d7f5d3SJohn Marino case would have been nice for gcc ia64 where BSWAP_LIMB is a mux1, but we
7386d7f5d3SJohn Marino can get that directly muxing a 4-byte ulong if it matters enough. */
7486d7f5d3SJohn Marino
7586d7f5d3SJohn Marino #if ! defined (BSWAP_ULONG)
7686d7f5d3SJohn Marino #define BSWAP_ULONG(dst, src) \
7786d7f5d3SJohn Marino do { \
7886d7f5d3SJohn Marino unsigned long __bswapl_src = (src); \
7986d7f5d3SJohn Marino unsigned long __bswapl_dst = 0; \
8086d7f5d3SJohn Marino int __i; \
8186d7f5d3SJohn Marino for (__i = 0; __i < sizeof(unsigned long); __i++) \
8286d7f5d3SJohn Marino { \
8386d7f5d3SJohn Marino __bswapl_dst = (__bswapl_dst << 8) | (__bswapl_src & 0xFF); \
8486d7f5d3SJohn Marino __bswapl_src >>= 8; \
8586d7f5d3SJohn Marino } \
8686d7f5d3SJohn Marino (dst) = __bswapl_dst; \
8786d7f5d3SJohn Marino } while (0)
8886d7f5d3SJohn Marino #endif
8986d7f5d3SJohn Marino
9086d7f5d3SJohn Marino /* x is bit reverse of y */
9186d7f5d3SJohn Marino /* Note the divides below are all exact */
9286d7f5d3SJohn Marino #define BITREV_ULONG(x,y) \
9386d7f5d3SJohn Marino do { \
9486d7f5d3SJohn Marino unsigned long __dst; \
9586d7f5d3SJohn Marino BSWAP_ULONG(__dst,y); \
9686d7f5d3SJohn Marino __dst = ((__dst>>4)&(ULONG_MAX/17)) | ((__dst<<4)&((ULONG_MAX/17)*16)); \
9786d7f5d3SJohn Marino __dst = ((__dst>>2)&(ULONG_MAX/5) ) | ((__dst<<2)&((ULONG_MAX/5)*4) ); \
9886d7f5d3SJohn Marino __dst = ((__dst>>1)&(ULONG_MAX/3) ) | ((__dst<<1)&((ULONG_MAX/3)*2) ); \
9986d7f5d3SJohn Marino (x) = __dst; \
10086d7f5d3SJohn Marino } while(0)
10186d7f5d3SJohn Marino /* above could be improved if cpu has a nibble/bit swap/muxing instruction */
10286d7f5d3SJohn Marino /* above code is serialized, possible to write as a big parallel expression */
10386d7f5d3SJohn Marino
10486d7f5d3SJohn Marino
10586d7f5d3SJohn Marino
10686d7f5d3SJohn Marino void
mpz_fac_ui(mpz_ptr x,unsigned long n)10786d7f5d3SJohn Marino mpz_fac_ui (mpz_ptr x, unsigned long n)
10886d7f5d3SJohn Marino {
10986d7f5d3SJohn Marino unsigned long z, stt;
11086d7f5d3SJohn Marino int i, j;
11186d7f5d3SJohn Marino mpz_t t1, st[8 * sizeof (unsigned long) + 1 - APCONST];
11286d7f5d3SJohn Marino mp_limb_t d[4];
11386d7f5d3SJohn Marino
11486d7f5d3SJohn Marino static const mp_limb_t table[] = { ONE_LIMB_FACTORIAL_TABLE };
11586d7f5d3SJohn Marino
11686d7f5d3SJohn Marino if (n < numberof (table))
11786d7f5d3SJohn Marino {
11886d7f5d3SJohn Marino MPZ_SET_1_NZ (x, table[n]);
11986d7f5d3SJohn Marino return;
12086d7f5d3SJohn Marino }
12186d7f5d3SJohn Marino
12286d7f5d3SJohn Marino /* NOTE : MUST have n>=3 here */
12386d7f5d3SJohn Marino ASSERT (n >= 3);
12486d7f5d3SJohn Marino /* for estimating the alloc sizes the calculation of these formula's is not
12586d7f5d3SJohn Marino exact and also the formulas are only approximations, also we ignore
12686d7f5d3SJohn Marino the few "side" calculations, correct allocation seems to speed up the
12786d7f5d3SJohn Marino small sizes better, having very little effect on the large sizes */
12886d7f5d3SJohn Marino
12986d7f5d3SJohn Marino /* estimate space for stack entries see below
13086d7f5d3SJohn Marino number of bits for n! is
13186d7f5d3SJohn Marino (1+log_2(2*pi)/2)-n*log_2(exp(1))+(n+1/2)*log_2(n)=
13286d7f5d3SJohn Marino 2.325748065-n*1.442695041+(n+0.5)*log_2(n) */
13386d7f5d3SJohn Marino umul_ppmm (d[1], d[0], (mp_limb_t) n, (mp_limb_t) FAC2OVERE);
13486d7f5d3SJohn Marino /* d[1] is 2n/e, d[0] ignored */
13586d7f5d3SJohn Marino count_leading_zeros (z, d[1]);
13686d7f5d3SJohn Marino z = GMP_LIMB_BITS - z - 1; /* z=floor(log_2(2n/e)) */
13786d7f5d3SJohn Marino umul_ppmm (d[1], d[0], (mp_limb_t) n, (mp_limb_t) z);
13886d7f5d3SJohn Marino /* d=n*floor(log_2(2n/e)) */
13986d7f5d3SJohn Marino d[0] = (d[0] >> 2) | (d[1] << (GMP_LIMB_BITS - 2));
14086d7f5d3SJohn Marino d[1] >>= 2;
14186d7f5d3SJohn Marino /* d=n*floor(log_2(2n/e))/4 */
14286d7f5d3SJohn Marino z = d[0] + 1; /* have to ignore any overflow */
14386d7f5d3SJohn Marino /* so z is the number of bits wanted for st[0] */
14486d7f5d3SJohn Marino
14586d7f5d3SJohn Marino
14686d7f5d3SJohn Marino if (n <= ((unsigned long) 1) << (APCONST))
14786d7f5d3SJohn Marino {
14886d7f5d3SJohn Marino mpz_realloc2 (x, 4 * z);
14986d7f5d3SJohn Marino ap_product_small (x, CNST_LIMB(2), CNST_LIMB(1), n - 1, 4L);
15086d7f5d3SJohn Marino return;
15186d7f5d3SJohn Marino }
15286d7f5d3SJohn Marino if (n <= ((unsigned long) 1) << (APCONST + 1))
15386d7f5d3SJohn Marino { /* use n!=odd(1,n)*(n/2)!*2^(n/2) */
15486d7f5d3SJohn Marino mpz_init2 (t1, 2 * z);
15586d7f5d3SJohn Marino mpz_realloc2 (x, 4 * z);
15686d7f5d3SJohn Marino ap_product_small (x, CNST_LIMB(2), CNST_LIMB(1), n / 2 - 1, 4L);
15786d7f5d3SJohn Marino ap_product_small (t1, CNST_LIMB(3), CNST_LIMB(2), (n - 1) / 2, 4L);
15886d7f5d3SJohn Marino mpz_mul (x, x, t1);
15986d7f5d3SJohn Marino mpz_clear (t1);
16086d7f5d3SJohn Marino mpz_mul_2exp (x, x, n / 2);
16186d7f5d3SJohn Marino return;
16286d7f5d3SJohn Marino }
16386d7f5d3SJohn Marino if (n <= ((unsigned long) 1) << (APCONST + 2))
16486d7f5d3SJohn Marino {
16586d7f5d3SJohn Marino /* use n!=C_2(1,n/2)^2*C_2(n/2,n)*(n/4)!*2^(n/2+n/4) all int divs
16686d7f5d3SJohn Marino so need (BITS_IN_N-APCONST+1)=(APCONST+3-APCONST+1)=4 stack entries */
16786d7f5d3SJohn Marino mpz_init2 (t1, 2 * z);
16886d7f5d3SJohn Marino mpz_realloc2 (x, 4 * z);
16986d7f5d3SJohn Marino for (i = 0; i < 4; i++)
17086d7f5d3SJohn Marino {
17186d7f5d3SJohn Marino mpz_init2 (st[i], z);
17286d7f5d3SJohn Marino z >>= 1;
17386d7f5d3SJohn Marino }
17486d7f5d3SJohn Marino odd_product (1, n / 2, st);
17586d7f5d3SJohn Marino mpz_set (x, st[0]);
17686d7f5d3SJohn Marino odd_product (n / 2, n, st);
17786d7f5d3SJohn Marino mpz_mul (x, x, x);
17886d7f5d3SJohn Marino ASSERT (n / 4 <= FACMUL4 + 6);
17986d7f5d3SJohn Marino ap_product_small (t1, CNST_LIMB(2), CNST_LIMB(1), n / 4 - 1, 4L);
18086d7f5d3SJohn Marino /* must have 2^APCONST odd numbers max */
18186d7f5d3SJohn Marino mpz_mul (t1, t1, st[0]);
18286d7f5d3SJohn Marino for (i = 0; i < 4; i++)
18386d7f5d3SJohn Marino mpz_clear (st[i]);
18486d7f5d3SJohn Marino mpz_mul (x, x, t1);
18586d7f5d3SJohn Marino mpz_clear (t1);
18686d7f5d3SJohn Marino mpz_mul_2exp (x, x, n / 2 + n / 4);
18786d7f5d3SJohn Marino return;
18886d7f5d3SJohn Marino }
18986d7f5d3SJohn Marino
19086d7f5d3SJohn Marino count_leading_zeros (stt, (mp_limb_t) n);
19186d7f5d3SJohn Marino stt = GMP_LIMB_BITS - stt + 1 - APCONST;
19286d7f5d3SJohn Marino
19386d7f5d3SJohn Marino for (i = 0; i < (signed long) stt; i++)
19486d7f5d3SJohn Marino {
19586d7f5d3SJohn Marino mpz_init2 (st[i], z);
19686d7f5d3SJohn Marino z >>= 1;
19786d7f5d3SJohn Marino }
19886d7f5d3SJohn Marino
19986d7f5d3SJohn Marino count_leading_zeros (z, (mp_limb_t) (n / 3));
20086d7f5d3SJohn Marino /* find z st 2^z>n/3 range for z is 1 <= z <= 8 * sizeof(unsigned long)-1 */
20186d7f5d3SJohn Marino z = GMP_LIMB_BITS - z;
20286d7f5d3SJohn Marino
20386d7f5d3SJohn Marino /*
20486d7f5d3SJohn Marino n! = 2^e * PRODUCT_{i=0}^{i=z-1} C_2( n/2^{i+1}, n/2^i )^{i+1}
20586d7f5d3SJohn Marino where 2^e || n! 3.2^z>n C_2(a,b)=PRODUCT of odd z such that a<z<=b
20686d7f5d3SJohn Marino */
20786d7f5d3SJohn Marino
20886d7f5d3SJohn Marino
20986d7f5d3SJohn Marino mpz_init_set_ui (t1, 1);
21086d7f5d3SJohn Marino for (j = 8 * sizeof (unsigned long) / 2; j != 0; j >>= 1)
21186d7f5d3SJohn Marino {
21286d7f5d3SJohn Marino MPZ_SET_1_NZ (x, 1);
21386d7f5d3SJohn Marino for (i = 8 * sizeof (unsigned long) - j; i >= j; i -= 2 * j)
21486d7f5d3SJohn Marino if ((signed long) z >= i)
21586d7f5d3SJohn Marino {
21686d7f5d3SJohn Marino odd_product (n >> i, n >> (i - 1), st);
21786d7f5d3SJohn Marino /* largest odd product when j=i=1 then we have
21886d7f5d3SJohn Marino odd_product(n/2,n,st) which is approx (2n/e)^(n/4)
21986d7f5d3SJohn Marino so log_base2(largest oddproduct)=n*log_base2(2n/e)/4
22086d7f5d3SJohn Marino number of bits is n*log_base2(2n/e)/4+1 */
22186d7f5d3SJohn Marino if (i != j)
22286d7f5d3SJohn Marino mpz_pow_ui (st[0], st[0], i / j);
22386d7f5d3SJohn Marino mpz_mul (x, x, st[0]);
22486d7f5d3SJohn Marino }
22586d7f5d3SJohn Marino if ((signed long) z >= j && j != 1)
22686d7f5d3SJohn Marino {
22786d7f5d3SJohn Marino mpz_mul (t1, t1, x);
22886d7f5d3SJohn Marino mpz_mul (t1, t1, t1);
22986d7f5d3SJohn Marino }
23086d7f5d3SJohn Marino }
23186d7f5d3SJohn Marino for (i = 0; i < (signed long) stt; i++)
23286d7f5d3SJohn Marino mpz_clear (st[i]);
23386d7f5d3SJohn Marino mpz_mul (x, x, t1);
23486d7f5d3SJohn Marino mpz_clear (t1);
23586d7f5d3SJohn Marino popc_limb (i, (mp_limb_t) n);
23686d7f5d3SJohn Marino mpz_mul_2exp (x, x, n - i);
23786d7f5d3SJohn Marino return;
23886d7f5d3SJohn Marino }
23986d7f5d3SJohn Marino
24086d7f5d3SJohn Marino /* start,step are mp_limb_t although they will fit in unsigned long */
24186d7f5d3SJohn Marino static void
ap_product_small(mpz_t ret,mp_limb_t start,mp_limb_t step,unsigned long count,unsigned long nm)24286d7f5d3SJohn Marino ap_product_small (mpz_t ret, mp_limb_t start, mp_limb_t step,
24386d7f5d3SJohn Marino unsigned long count, unsigned long nm)
24486d7f5d3SJohn Marino {
24586d7f5d3SJohn Marino unsigned long a;
24686d7f5d3SJohn Marino mp_limb_t b;
24786d7f5d3SJohn Marino
24886d7f5d3SJohn Marino ASSERT (count <= (((unsigned long) 1) << APCONST));
24986d7f5d3SJohn Marino /* count can never be zero ? check this and remove test below */
25086d7f5d3SJohn Marino if (count == 0)
25186d7f5d3SJohn Marino {
25286d7f5d3SJohn Marino MPZ_SET_1_NZ (ret, 1);
25386d7f5d3SJohn Marino return;
25486d7f5d3SJohn Marino }
25586d7f5d3SJohn Marino if (count == 1)
25686d7f5d3SJohn Marino {
25786d7f5d3SJohn Marino MPZ_SET_1_NZ (ret, start);
25886d7f5d3SJohn Marino return;
25986d7f5d3SJohn Marino }
26086d7f5d3SJohn Marino switch (nm)
26186d7f5d3SJohn Marino {
26286d7f5d3SJohn Marino case 1:
26386d7f5d3SJohn Marino MPZ_SET_1_NZ (ret, start);
26486d7f5d3SJohn Marino b = start + step;
26586d7f5d3SJohn Marino for (a = 0; a < count - 1; b += step, a++)
26686d7f5d3SJohn Marino MPZ_MUL_1_POS (ret, ret, b);
26786d7f5d3SJohn Marino return;
26886d7f5d3SJohn Marino case 2:
26986d7f5d3SJohn Marino MPZ_SET_1_NZ (ret, start * (start + step));
27086d7f5d3SJohn Marino if (count == 2)
27186d7f5d3SJohn Marino return;
27286d7f5d3SJohn Marino for (b = start + 2 * step, a = count / 2 - 1; a != 0;
27386d7f5d3SJohn Marino a--, b += 2 * step)
27486d7f5d3SJohn Marino MPZ_MUL_1_POS (ret, ret, b * (b + step));
27586d7f5d3SJohn Marino if (count % 2 == 1)
27686d7f5d3SJohn Marino MPZ_MUL_1_POS (ret, ret, b);
27786d7f5d3SJohn Marino return;
27886d7f5d3SJohn Marino case 3:
27986d7f5d3SJohn Marino if (count == 2)
28086d7f5d3SJohn Marino {
28186d7f5d3SJohn Marino MPZ_SET_1_NZ (ret, start * (start + step));
28286d7f5d3SJohn Marino return;
28386d7f5d3SJohn Marino }
28486d7f5d3SJohn Marino MPZ_SET_1_NZ (ret, start * (start + step) * (start + 2 * step));
28586d7f5d3SJohn Marino if (count == 3)
28686d7f5d3SJohn Marino return;
28786d7f5d3SJohn Marino for (b = start + 3 * step, a = count / 3 - 1; a != 0;
28886d7f5d3SJohn Marino a--, b += 3 * step)
28986d7f5d3SJohn Marino MPZ_MUL_1_POS (ret, ret, b * (b + step) * (b + 2 * step));
29086d7f5d3SJohn Marino if (count % 3 == 2)
29186d7f5d3SJohn Marino b = b * (b + step);
29286d7f5d3SJohn Marino if (count % 3 != 0)
29386d7f5d3SJohn Marino MPZ_MUL_1_POS (ret, ret, b);
29486d7f5d3SJohn Marino return;
29586d7f5d3SJohn Marino default: /* ie nm=4 */
29686d7f5d3SJohn Marino if (count == 2)
29786d7f5d3SJohn Marino {
29886d7f5d3SJohn Marino MPZ_SET_1_NZ (ret, start * (start + step));
29986d7f5d3SJohn Marino return;
30086d7f5d3SJohn Marino }
30186d7f5d3SJohn Marino if (count == 3)
30286d7f5d3SJohn Marino {
30386d7f5d3SJohn Marino MPZ_SET_1_NZ (ret, start * (start + step) * (start + 2 * step));
30486d7f5d3SJohn Marino return;
30586d7f5d3SJohn Marino }
30686d7f5d3SJohn Marino MPZ_SET_1_NZ (ret,
30786d7f5d3SJohn Marino start * (start + step) * (start + 2 * step) * (start +
30886d7f5d3SJohn Marino 3 * step));
30986d7f5d3SJohn Marino if (count == 4)
31086d7f5d3SJohn Marino return;
31186d7f5d3SJohn Marino for (b = start + 4 * step, a = count / 4 - 1; a != 0;
31286d7f5d3SJohn Marino a--, b += 4 * step)
31386d7f5d3SJohn Marino MPZ_MUL_1_POS (ret, ret,
31486d7f5d3SJohn Marino b * (b + step) * (b + 2 * step) * (b + 3 * step));
31586d7f5d3SJohn Marino if (count % 4 == 2)
31686d7f5d3SJohn Marino b = b * (b + step);
31786d7f5d3SJohn Marino if (count % 4 == 3)
31886d7f5d3SJohn Marino b = b * (b + step) * (b + 2 * step);
31986d7f5d3SJohn Marino if (count % 4 != 0)
32086d7f5d3SJohn Marino MPZ_MUL_1_POS (ret, ret, b);
32186d7f5d3SJohn Marino return;
32286d7f5d3SJohn Marino }
32386d7f5d3SJohn Marino }
32486d7f5d3SJohn Marino
32586d7f5d3SJohn Marino /* return value in st[0]
32686d7f5d3SJohn Marino odd_product(l,h)=sqrt((h/e)^h/(l/e)^l) using Stirling approx and e=exp(1)
32786d7f5d3SJohn Marino so st[0] needs enough bits for above, st[1] needs half these bits and
32886d7f5d3SJohn Marino st[2] needs 1/4 of these bits etc */
32986d7f5d3SJohn Marino static void
odd_product(unsigned long low,unsigned long high,mpz_t * st)33086d7f5d3SJohn Marino odd_product (unsigned long low, unsigned long high, mpz_t * st)
33186d7f5d3SJohn Marino {
33286d7f5d3SJohn Marino unsigned long stc = 1, stn = 0, n, y, mask, a, nm = 1;
33386d7f5d3SJohn Marino signed long z;
33486d7f5d3SJohn Marino
33586d7f5d3SJohn Marino low++;
33686d7f5d3SJohn Marino if (low % 2 == 0)
33786d7f5d3SJohn Marino low++;
33886d7f5d3SJohn Marino if (high == 0)
33986d7f5d3SJohn Marino high = 1;
34086d7f5d3SJohn Marino if (high % 2 == 0)
34186d7f5d3SJohn Marino high--;
34286d7f5d3SJohn Marino /* must have high>=low ? check this and remove test below */
34386d7f5d3SJohn Marino if (high < low)
34486d7f5d3SJohn Marino {
34586d7f5d3SJohn Marino MPZ_SET_1_NZ (st[0], 1);
34686d7f5d3SJohn Marino return;
34786d7f5d3SJohn Marino }
34886d7f5d3SJohn Marino if (high == low)
34986d7f5d3SJohn Marino {
35086d7f5d3SJohn Marino MPZ_SET_1_NZ (st[0], low);
35186d7f5d3SJohn Marino return;
35286d7f5d3SJohn Marino }
35386d7f5d3SJohn Marino if (high <= FACMUL2 + 2)
35486d7f5d3SJohn Marino {
35586d7f5d3SJohn Marino nm = 2;
35686d7f5d3SJohn Marino if (high <= FACMUL3 + 4)
35786d7f5d3SJohn Marino {
35886d7f5d3SJohn Marino nm = 3;
35986d7f5d3SJohn Marino if (high <= FACMUL4 + 6)
36086d7f5d3SJohn Marino nm = 4;
36186d7f5d3SJohn Marino }
36286d7f5d3SJohn Marino }
36386d7f5d3SJohn Marino high = (high - low) / 2 + 1; /* high is now count,high<=2^(BITS_PER_ULONG-1) */
36486d7f5d3SJohn Marino if (high <= (((unsigned long) 1) << APCONST))
36586d7f5d3SJohn Marino {
36686d7f5d3SJohn Marino ap_product_small (st[0], (mp_limb_t) low, CNST_LIMB(2), high, nm);
36786d7f5d3SJohn Marino return;
36886d7f5d3SJohn Marino }
36986d7f5d3SJohn Marino count_leading_zeros (n, (mp_limb_t) high);
37086d7f5d3SJohn Marino /* assumes clz above is LIMB based not NUMB based */
37186d7f5d3SJohn Marino n = GMP_LIMB_BITS - n - APCONST;
37286d7f5d3SJohn Marino mask = (((unsigned long) 1) << n);
37386d7f5d3SJohn Marino a = mask << 1;
37486d7f5d3SJohn Marino mask--;
37586d7f5d3SJohn Marino /* have 2^(BITS_IN_N-APCONST) iterations so need
37686d7f5d3SJohn Marino (BITS_IN_N-APCONST+1) stack entries */
37786d7f5d3SJohn Marino for (z = mask; z >= 0; z--)
37886d7f5d3SJohn Marino {
37986d7f5d3SJohn Marino BITREV_ULONG (y, z);
38086d7f5d3SJohn Marino y >>= (BITS_PER_ULONG - n);
38186d7f5d3SJohn Marino ap_product_small (st[stn],
38286d7f5d3SJohn Marino (mp_limb_t) (low + 2 * ((~y) & mask)), (mp_limb_t) a,
38386d7f5d3SJohn Marino (high + y) >> n, nm);
38486d7f5d3SJohn Marino ASSERT (((high + y) >> n) <= (((unsigned long) 1) << APCONST));
38586d7f5d3SJohn Marino stn++;
38686d7f5d3SJohn Marino y = stc++;
38786d7f5d3SJohn Marino while ((y & 1) == 0)
38886d7f5d3SJohn Marino {
38986d7f5d3SJohn Marino mpz_mul (st[stn - 2], st[stn - 2], st[stn - 1]);
39086d7f5d3SJohn Marino stn--;
39186d7f5d3SJohn Marino y >>= 1;
39286d7f5d3SJohn Marino }
39386d7f5d3SJohn Marino }
39486d7f5d3SJohn Marino ASSERT (stn == 1);
39586d7f5d3SJohn Marino return;
39686d7f5d3SJohn Marino }
397