/*
 * Copyright (c) 1994 by Landon Curt Noll.  All Rights Reserved.
 *
 * Permission to use, copy, modify, and distribute this software and
 * its documentation for any purpose and without fee is hereby granted,
 * provided that the above copyright, this permission notice and text
 * this comment, and the disclaimer below appear in all of the following:
 *
 *	supporting documentation
 *	source copies
 *	source works derived from this source
 *	binaries derived from this source or from derived source
 *
 * LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
 * EVENT SHALL LANDON CURT NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 *
 * chongo was here	/\../\
 */

#include "zmath.h"
#include "prime.h"
#include "jump.h"

/*
 * When performing a probabilistic primality test, check to see
 * if the number has a factor <= PTEST_PRECHECK.
 *
 * XXX - what should this value be?  Perhaps this should be a function
 *	 of the size of the text value and the number of tests?
 */
#define PTEST_PRECHECK ((FULL)101)

/*
 * product of primes that fit into a long
 */
static FULL pfact_tbl[MAX_PFACT_VAL+1] = {
    1, 1, 2, 6, 6, 30, 30, 210, 210, 210, 210, 2310, 2310, 30030, 30030,
    30030, 30030, 510510, 510510, 9699690, 9699690, 9699690, 9699690,
    223092870, 223092870, 223092870, 223092870, 223092870, 223092870
#if FULL_BITS == 64
    , U(6469693230), U(6469693230), U(200560490130), U(200560490130),
    U(200560490130), U(200560490130), U(200560490130), U(200560490130),
    U(7420738134810), U(7420738134810), U(7420738134810), U(7420738134810),
    U(304250263527210), U(304250263527210), U(13082761331670030),
    U(13082761331670030), U(13082761331670030), U(13082761331670030),
    U(614889782588491410), U(614889782588491410), U(614889782588491410),
    U(614889782588491410), U(614889782588491410), U(614889782588491410)
#endif
};

/*
 * determine the top 1 bit of a 8 bit value:
 *
 *	topbit[0] == 0 by convention
 *	topbit[x] gives the highest 1 bit of x
 */
static unsigned char topbit[256] = {
    0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
};

/*
 * integer square roots of powers of 2
 *
 * isqrt_pow2[x] == (int)(sqrt(2 to the x power))	      (for 0 <= x < 64)
 *
 * We have enough table entries for a FULL that is 64 bits long.
 */
static FULL isqrt_pow2[64] = {
    1, 1, 2, 2, 4, 5, 8, 11, 					/*  0 ..  7 */
    16, 22, 32, 45, 64, 90, 128, 181,				/*  8 .. 15 */
    256, 362, 512, 724, 1024, 1448, 2048, 2896, 		/* 16 .. 23 */
    4096, 5792, 8192, 11585, 16384, 23170, 32768, 46340, 	/* 24 .. 31 */
    65536, 92681, 131072, 185363,				/* 32 .. 35 */
    262144, 370727, 524288, 741455,				/* 36 .. 39 */
    1048576, 1482910, 2097152, 2965820,				/* 40 .. 43 */
    4194304, 5931641, 8388608, 11863283,			/* 44 .. 47 */
    16777216, 23726566, 33554432, 47453132,			/* 48 .. 51 */
    67108864, 94906265, 134217728, 189812531,			/* 52 .. 55 */
    268435456, 379625062, 536870912, 759250124,			/* 56 .. 59 */
    1073741824, 1518500249, 0x80000000, 0xb504f333		/* 60 .. 63 */
};

/*
 * static functions
 */
static FULL fsqrt MATH_PROTO((FULL v));		/* quick square root of v */
static long pix MATH_PROTO((FULL x));		/* pi of x */
static FULL small_factor MATH_PROTO((ZVALUE n, FULL limit));   /* factor or 0 */


/*
 * Determine if a value is a small (32 bit) prime
 *
 * Returns:
 *	1	z is a prime <= MAX_SM_VAL
 *	0	z is not a prime <= MAX_SM_VAL
 *	-1	z > MAX_SM_VAL
 */
FLAG
zisprime(z)
	ZVALUE z;
{
	FULL n;			/* number to test */
	FULL isqr;		/* factor limit */
	unsigned short *tp;	/* pointer to a prime factor */

	/* negative values as well as 0 and 1 are not prime */
	if (zisleone(z)) {
		/* in func.c, neg values are caught and return -1 */
		return 0;
	}

	/* even numbers > 2 are not prime */
	if (ziseven(z)) {
		/*
		 * "2 is the greatest odd prime because it is the least even!"
		 *					- Dr. Dan Jurca  1978
		 */
		return zisabstwo(z);
	}

	/* ignore non-small values */
	if (zge32b(z)) {
		return -1;
	}

	/* we now know that we are dealing with a value 0 <= n < 2^32 */
	n = ztofull(z);

	/* lookup small cases in pr_map */
	if (n <= MAX_MAP_VAL) {
		return (pr_map_bit(n) ? 1 : 0);
	}

	/* ignore Saber-C warning #530 about empty for statement */
	/*	  ok to ignore in proc zisprime */
	/* a number >=2^16 and < 2^32 */
	for (isqr=fsqrt(n), tp=prime; (*tp <= isqr) && (n % *tp); ++tp) {
	}
 	return ((*tp <= isqr && *tp != 1) ? 0 : 1);
}


/*
 * Determine the next small (32 bit) prime > a 32 bit value.
 *
 * Returns:
 *	0	next prime is 2^32+15
 *	1	z >= 2^32
 *	smallest prime > z otherwise
 */
FULL
znprime(z)
	ZVALUE z;		/* search point */
{
	FULL n;			/* search point */

	/* negative values are not prime */
	if (zisneg(z)) {
		return (FULL)2;
	}

	/* ignore large values */
	if (zge32b(z)) {
		return (FULL)1;
	}

	/* deal a search point of 0 or 1 */
	if (zisabsleone(z)) {
		return (FULL)2;
	}

	/* deal with returning a value that is beyond our reach */
	n = ztofull(z);
	if (n >= MAX_SM_PRIME) {
		return (FULL)0;
	}

	/* return the next prime */
	return next_prime(n);
}


/*
 * Compute the next prime beyond a small (32 bit) value.
 *
 * This function assumes that 2 <= n < 2^32-5.
 */
FULL
next_prime(n)
	FULL n;			/* search point */
{
	unsigned short *tp;	/* pointer to a prime factor */
	unsigned char *j;	/* current jump increment */
	int tmp;		/* temp stroage */

	/* find our search point */
	n = ((n & 0x1) ? n+2 : n+1);

	/* if we can just search the bit map, then serch it */
	if (n <= MAX_MAP_PRIME) {

		/* search until we find a 1 bit */
		while (pr_map_bit(n) == 0) {
			n += (FULL)2;
		}

	/* too large for our table, find the next prime the hard way */
	} else {
		FULL isqr;		/* factor limit */

		/*
		 * Our search for a prime may cause us to increment n over
		 * a perfect square, but never two perfect squares.  The largest
		 * prime gap <= 2614941711251 is 651.  Shankes conjectures that
		 * the largest gap below P is about ln(P)^2.
		 *
		 * The value fsqrt(n)^2 will always be the perfect square
		 * that is <= n.  Given the smallness of prime gaps we will
		 * deal with, we know that n could carry us across the next
		 * perfect square (fsqrt(n)+1)^2 but not the following
		 * perfect square (fsqrt(n)+2)^2.
		 *
		 * Now the factor search limit for values < (fsqrt(n)+2)^2
		 * is the same limit for (fsqrt(n)+1)^2; namely fsqrt(n)+1.
		 * Therefore setting our limit at fsqrt(n)+1 and never
		 * bothering with it after that is safe.
		 */
		isqr = fsqrt(n)+1;

		/*
		 * If our factor limit is even, then we can reduce it to
		 * the next lowest odd value.  We already tested if n
		 * was even and all of our remaining potential factors
		 * are odd.
		 */
		if ((isqr & 0x1) == 0) {
			--isqr;
		}

		/*
		 * Skip to next value not divisible by a trivial prime.
		 */
		n = firstjmp(n, tmp);
		j = jmp + jmpptr(n);

		/*
		 * Look for tiny prime factors of increasing n until we
		 * find a prime.
		 */
		do {
			/* ignore Saber-C warning #530 - empty for statement */
			/*	  ok to ignore in proc next_prime */
			/* XXX - speed up test for large n by using gcds */
			/* find a factor, or give up if not found */
			for (tp=JPRIME; (*tp <= isqr) && (n % *tp); ++tp) {
			}
		} while (*tp <= isqr && *tp != 1 && (n += nxtjmp(j)));
	}

	/* return the prime that we found */
	return n;
}


/*
 * Determine the previous small (32 bit) prime < a 32 bit value
 *
 * Returns:
 *	1	z >= 2^32
 *	0	z <= 2
 *	smallest prime < z otherwise
 */
FULL
zpprime(z)
	ZVALUE z;		/* search point */
{
	unsigned short *tp;	/* pointer to a prime factor */
	FULL isqr;		/* isqrt(z) */
	FULL n;			/* search point */
	unsigned char *j;	/* current jump increment */
	int tmp;		/* temp stroage */

	/* negative values are not prime */
	if (zisneg(z)) {
		return (FULL)0;
	}

	/* ignore large values */
	if (zge32b(z)) {
		return (FULL)1;
	}

	/* deal with special case small values */
	n = ztofull(z);
	switch (n) {
	case 0:
	case 1:
	case 2:
		/* ignore values <= 2 */
		return (FULL)0;
	case 3:
		/* 3 returns the only even prime */
		return (FULL)2;
	}

	/* deal with values above the bit map */
	if (n > NXT_MAP_PRIME) {

		/* find our search point */
		n = ((n & 0x1) ? n-2 : n-1);

		/* our factor limit - see next_prime for why this works */
		isqr = fsqrt(n)+1;
		if ((isqr & 0x1) == 0) {
			--isqr;
		}

		/*
		 * Skip to previous value not divisible by a trivial prime.
		 */
		tmp = jmpindxval(n);
		if (tmp >= 0) {

			/* find next value not divisible by a trivial prime */
			n += tmp;

			/* find the previous jump index */
			j = jmp + jmpptr(n);

			/* jump back */
			n -= prevjmp(j);

		/* already not divisible by a trivial prime */
		} else {
			/* find the current jump index */
			j = jmp + jmpptr(n);
		}

		/* factor values until we find a prime */
		do {
			/* ignore Saber-C warning #530 - empty for statement */
			/*	  ok to ignore in proc zpprime */
			/* XXX - speed up test for large n by using gcds */
			/* find a factor, or give up if not found */
			for (tp=prime; (*tp <= isqr) && (n % *tp); ++tp) {
			}
		} while (*tp <= isqr && *tp != 1 && (n -= prevjmp(j)));

	/* deal with values within the bit map */
	} else if (n <= MAX_MAP_PRIME) {

		/* find our search point */
		n = ((n & 0x1) ? n-2 : n-1);

		/* search until we find a 1 bit */
		while (pr_map_bit(n) == 0) {
			n -= (FULL)2;
		}

	/* deal with values that could cross into the bit map */
	} else {
		/* MAX_MAP_PRIME < n <= NXT_MAP_PRIME returns MAX_MAP_PRIME */
		return MAX_MAP_PRIME;
	}

	/* return what we found */
	return n;
}


/*
 * Compute the number of primes <= a ZVALUE that can fit into a FULL
 *
 * Returns:
 *	-1	error
 *	>=0	number of primes <= x
 */
long
zpix(z)
	ZVALUE z;		/* compute primes <= z */
{
	/* pi(<0) is always 0 */
	if (zisneg(z)) {
		return (long)0;
	}

	/* firewall */
	if (zge32b(z)) {
		return (long)-1;
	}
	return pix(ztofull(z));
}


/*
 * Compute the number of primes <= a ZVALUE
 *
 * Returns:
 *	-1	error
 *	>=0	number of primes <= x
 */
static long
pix(x)
	FULL x;			/* value of z */
{
	long count;		/* pi(x) */
	FULL top;		/* top of the range to test */
	unsigned short *tp;	/* pointer to a tiny prime */
	FULL i;

	/* compute pi(x) using the 2^8 step table */
	if (x <= MAX_PI10B) {

		/* x within the prime table, so use it */
		if (x < MAX_MAP_PRIME) {
			/* firewall - pix(x) ==0 for x < 2 */
			if (x < 2) {
				count = 0;

			} else {
				/* determine how and where we will count */
				if (x < 1024) {
					count = 1;
					tp = prime;
				} else {
					count = pi10b[x>>10];
					tp = prime+count-1;
				}
				/* count primes in the table */
				while (*tp++ <= x) {
					++count;
				}
			}

		/* x is larger than the prime table, so count the hard way */
		} else {

			/* case: count down from pi18b entry to x */
			if (x & 0x200) {
				top = (x | 0x3ff);
				count = pi10b[(top+1)>>10];
				for (i=next_prime(x); i <= top;
				     i=next_prime(i)) {
					--count;
				}

			/* case: count up from pi10b entry to x */
			} else {
				count = pi10b[x>>10];
				for (i=next_prime(x&(~0x3ff));
				     i <= x; i = next_prime(i)) {
					++count;
				}
			}
		}

	/* compute pi(x) using the 2^18 interval table */
	} else {

		/* compute sum of intervals up to our interval */
		for (count=0, i=0; i < (x>>18); ++i) {
			count += pi18b[i];
		}

		/* case: count down from pi18b entry to x */
		if (x & 0x20000) {
			top = (x | 0x3ffff);
			count += pi18b[i];
			if (top > MAX_SM_PRIME) {
				if (x < MAX_SM_PRIME) {
					for (i=next_prime(x); i < MAX_SM_PRIME;
					     i=next_prime(i)) {
						--count;
					}
					--count;
				}
			} else {
				for (i=next_prime(x); i<=top; i=next_prime(i)) {
					--count;
				}
			}

		/* case: count up from pi18b entry to x */
		} else {
			for (i=next_prime(x&(~0x3ffff));
			     i <= x; i = next_prime(i)) {
				++count;
			}
		}
	}
	return count;
}


/*
 * Compute the smallest prime factor < limit
 *
 * Returns:
 *	-1	error, limit >= 2^32
 *	0	no factor found, res is not changed
 *	1	factor found, res (if non-NULL) is smallest prime factor
 *
 * NOTE: This routine will not return a factor == the test value
 *	 except when the test value is 1 or -1.
 */
FLAG
zfactor(n, zlimit, res)
	ZVALUE n;		/* number to factor */
	ZVALUE zlimit;		/* ending search point */
	ZVALUE *res;		/* factor, if found, or NULL */
{
	FULL f;			/* factor found, or 0 */

	/*
	 * determine the limit
	 */
	if (zge32b(zlimit)) {
		/* limit is too large to be reasonable */
		return -1;
	}

	/*
	 * find the smallest factor <= limit, if possible
	 */
	f = small_factor(n, ztofull(zlimit));

	/*
	 * report the results
	 */
	if (f > 0) {
		/* return factor if requested */
		if (res) {
			utoz(f, res);
		}
		/* report a factor was found */
		return 1;
	}
	/* no factor was found */
	return 0;
}


/*
 * Find a smallest prime factor <= some small (32 bit) limit of a value
 *
 * Returns:
 *	0	no prime <= the limit was found
 *	!= 0	the smallest prime factor
 */
static FULL
small_factor(z, limit)
	ZVALUE z;		/* number to factor */
	FULL limit;		/* largest factor we will test */
{
	FULL top;		/* current max factor level */
	unsigned short *tp;	/* pointer to a tiny prime */
	FULL factlim;		/* highest factor to test */
	unsigned short *p;	/* test factor */
	FULL factor;		/* test factor */
	HALF tlim;		/* limit on prime table use */
	HALF divval[2];		/* divisor value */
	ZVALUE div;		/* test factor/divisor */
	ZVALUE tmp;

	/*
	 * catch impossible ranges
	 */
	if (limit < 2) {
		/* range is too small */
		return 0;
	}

	/*
	 * perform the even test
	 */
	if (ziseven(z)) {
		if (zistwo(z)) {
			/* z is 2, so don't return 2 as a factor */
			return 0;
		}
		return 2;

	/*
	 * value is odd
	 */
	} else if (limit == 2) {
		/* limit is 2, value is odd, no factors will ever be found */
		return 0;
	}

	/*
	 * force the factor limit to be odd
	 */
	if ((limit & 0x1) == 0) {
		--limit;
	}

	/*
	 * case: number to factor fits into a FULL
	 */
	if (!zgtmaxufull(z)) {
		FULL val = ztofull(z);	/* find the smallest factor of val */
		FULL isqr;		/* sqrt of val */
#if FULL_BITS == 64
		unsigned char *j;	/* current jump increment */
#endif

		/*
		 * special case: val is a prime <= MAX_MAP_PRIME
		 */
		if (val <= MAX_MAP_PRIME && pr_map_bit(val)) {
			/* z is prime, so no factors will be found */
			return 0;
		}

		/*
		 * we need not search above the sqrt of val
		 */
		isqr = fsqrt(val);
		if (limit > isqr) {
			/* limit is lagest odd value <= sqrt of val */
			limit = ((isqr & 0x1) ? isqr : isqr-1);
		}

		/*
		 * search for a small prime factor
		 */
		top = ((limit < MAX_MAP_VAL) ? limit : MAX_MAP_VAL);
		for (tp = prime; *tp <= top; ++tp) {
			if (val%(*tp) == 0) {
				return ((FULL)*tp);
			}
		}

#if FULL_BITS == 64
		/*
		 * Our search will carry us beyond the prime table.  We will
		 * continue to values until we reach our limit or until a
		 * factor is found.
		 *
		 * It is faster to simply test odd values and ignore non-prime
		 * factors because the work needed to find the next prime is
		 * more than the work one saves in not factor with non-prime
		 * values.
		 *
		 * We can improve on this method by skipping odd values that
		 * are a multiple of 3, 5, 7 and 11.  We use a table of
		 * bytes that indicate the offsets between odd values that
		 * are not a multiple of 3,4,5,7 & 11.
		 */
		/* XXX - speed up test for large z by using gcds */
		j = jmp + jmpptr(NXT_MAP_PRIME);
		for (top=NXT_MAP_PRIME; top <= limit; top += nxtjmp(j)) {
			if ((val % top) == 0) {
				return top;
			}
		}
#endif /* FULL_BITS == 64 */

		/* no prime factors found */
		return 0;
	}

	/*
	 * Find a factor of a value that is too large to fit into a FULL.
	 *
	 * determine if/what our sqrt factor limit will be
	 */
	if (zge64b(z)) {
		/* we have no factor limit, avoid highest factor */
		factlim = MAX_SM_PRIME-1;
	} else if (zge32b(z)) {
		/* determine if limit is too small to matter */
		if (limit < BASE) {
			factlim = limit;
		} else {
			/* find the isqrt(z) */
			if (zsqrt(z, &tmp)) {
				/* sqrt is exact */
				factlim = ztofull(tmp);
			} else {
				/* sqrt is inexact */
				factlim = ztofull(tmp)+1;
			}
			zfree(tmp);

			/* avoid highest factor */
			if (factlim >= MAX_SM_PRIME) {
				factlim = MAX_SM_PRIME-1;
			}
		}
	} else {
		/* determine our factor limit */
		factlim = fsqrt(ztofull(z));
		if (factlim >= MAX_SM_PRIME) {
			factlim = MAX_SM_PRIME-1;
		}
	}
	if (factlim > limit) {
		factlim = limit;
	}

	/*
	 * walk the prime table looking for factors
	 *
	 * XXX - consider using gcd of products of primes to speed this
	 *	 section up
	 */
	tlim = (HALF)((factlim >= MAX_MAP_PRIME) ? MAX_MAP_PRIME-1 : factlim);
	div.sign = 0;
	div.v = divval;
	div.len = 1;
	for (p=prime; (HALF)*p <= tlim; ++p) {

		/* setup factor */
		div.v[0] = (HALF)(*p);

		/* divide */
		zmod(z, div, &tmp);

		/* check if we have a remainder */
		if (ziszero(tmp)) {
			/* p is a factor */
			zfree(tmp);
			return (FULL)(*p);
		}
		zfree(tmp);
	}
	if ((FULL)*p > factlim) {
		/* no factor found */
		return (FULL)0;
	}

	/*
	 * test the highest factor possible
	 */
	div.v[0] = MAX_MAP_PRIME;
	/* divide */
	zmod(z, div, &tmp);
	/* check if we have a remainder */
	if (ziszero(tmp)) {
		/* factor is found */
		zfree(tmp);
		return (FULL)MAX_MAP_PRIME;
	}
	zfree(tmp);

	/*
	 * generate higher test factors as needed
	 *
	 * XXX - consider using gcd of products of primes to speed this
	 *	 section up
	 */
#if BASEB == 16
	div.len = 2;
#endif
	for(factor = NXT_MAP_PRIME; factor <= factlim;
	    factor = next_prime(factor)) {

		/* setup factor */
#if BASEB == 32
		div.v[0] = factor;
#else
		div.v[0] = (factor & BASE1);
		div.v[1] = (factor >> BASEB);
#endif

		/* divide */
		zmod(z, div, &tmp);

		/* check if we have a remainder */
		if (ziszero(tmp)) {
			/* factor is found */
			zfree(tmp);
			return (FULL)(factor);
		}
		zfree(tmp);
	}
	if (factor >= factlim) {
		/* no factor found */
		return (FULL)0;
	}

	/*
	 * test the highest factor possible
	 */
#if BASEB == 32
	div.v[0] = MAX_SM_PRIME;
#else
	div.v[0] = (MAX_SM_PRIME & BASE1);
	div.v[1] = (MAX_SM_PRIME >> BASEB);
#endif
	/* divide */
	zmod(z, div, &tmp);
	/* check if we have a remainder */
	if (ziszero(tmp)) {
		/* factor is found */
		zfree(tmp);
		return (FULL)MAX_SM_PRIME;
	}
	zfree(tmp);

	/*
	 * no factor found
	 */
	return (FULL)0;
}


/*
 * Compute the product of the primes up to the specified number.
 */
void
zpfact(z, dest)
	ZVALUE z, *dest;
{
	long n;			/* limiting number to multiply by */
	long p;			/* current prime */
	unsigned short *tp;	/* pointer to a tiny prime */
	unsigned char *j;	/* current jump increment */
	ZVALUE res, temp;

	/* firewall */
	if (zisneg(z))
		math_error("Negative argument for factorial");
	if (zge24b(z))
		math_error("Very large factorial");
	n = ztolong(z);

	/*
	 * Deal with table lookup pfact values
	 */
	if (n <= MAX_PFACT_VAL) {
		utoz(pfact_tbl[n], dest);
		return;
	}

	/*
	 * Multiply by the primes in the static table
	 */
	utoz(pfact_tbl[MAX_PFACT_VAL], &res);
	for (tp=(&prime[NXT_PFACT_VAL]); *tp != 1 && *tp <= n; ++tp) {
		zmuli(res, *tp, &temp);
		zfree(res);
		res = temp;
	}

	/*
	 * if needed, multiply by primes beyond the static table
	 */
	j = jmp + jmpptr(NXT_MAP_PRIME);
	for (p = NXT_MAP_PRIME; p <= n; p += nxtjmp(j)) {
		FULL isqr;	/* isqrt(p) */

		/* our factor limit - see next_prime for why this works */
		isqr = fsqrt(p)+1;
		if ((isqr & 0x1) == 0) {
			--isqr;
		}

		/* ignore Saber-C warning #530 about empty for statement */
		/*	  ok to ignore in proc zpfact */
		/* find the next prime */
		for (tp=prime; (*tp <= isqr) && (p % *tp); ++tp) {
		}
		if (*tp <= isqr && *tp != 1) {
			continue;
		}

		/* multiply by the next prime */
		zmuli(res, p, &temp);
		zfree(res);
		res = temp;
	}
	*dest = res;
}


/*
 * Perform a probabilistic primality test (algorithm P in Knuth vol2, 4.5.4).
 * Returns FALSE if definitely not prime, or TRUE if probably prime.
 * Count determines how many times to check for primality.
 * The chance of a non-prime passing this test is less than (1/4)^count.
 * For example, a count of 100 fails for only 1 in 10^60 numbers.
 *
 * It is interesting to note that ptest(a,1,x) (for any x >= 0) of this
 * test will always return TRUE for a prime, and rarely return TRUE for
 * a non-prime.  The 1/4 is appears in practice to be a poor upper
 * bound.  Even so the only result that is EXACT and TRUE is when
 * this test returns FALSE for a non-prime.  When ptest returns TRUE,
 * one cannot determine if the value in question is prime, or the value
 * is one of those rare non-primes that produces a false positive.
 *
 * The absolute value of count determines how many times to check
 * for primality.  If count M 0, then the trivial factor check is
 * omitted.  The skip value determine how many tests to initially skip.
 *
 * NOTE: We assume that (abs(skip)*2 + 3) + (abs(count)*2) fits
 *	 into a FULL.  The qprimetest() call restricts skip and
 *	 count to 24 bit values, so it should always fit into a FULL.
 *
 */
BOOL
zprimetest(z, count, skip)
	ZVALUE z;		/* number to test for primeness */
	long count;
	long skip;
{
	long limit;		/* test odd values from skip up to limit */
	long base;		/* odd test base */
	ZVALUE zbase;		/* base as a ZVALUE */
	long ij, ik;
	ZVALUE zm1, z1, z2, z3;

	/*
	 * firewall - values <= 1 are never prime
	 */
	if (zisleone(z)) {
		return 0;
	}

	/*
	 * firewall - All even values, expect 2, are not prime
	 */
	if (ziseven(z))	{
		return zisabstwo(z);
	}

	/*
	 * we know that z is an odd value > 1
	 */

	/*
	 * Perform trivial checks if count is not negative
	 */
	if (count >= 0) {

		/*
		 * If the number is a small (32 bit) value, do a direct test
		 */
		if (!zge32b(z)) {
			return zisprime(z);
		}

		/*
		 * See if the number has a tiny factor.
		 */
		if (small_factor(z, PTEST_PRECHECK) != 0) {
			/* a tiny factor was found */
			return FALSE;
		}

		/*
		 * If our count is zero, do nothing more
		 */
		if (count == 0) {
			/* no test was done, so no test failed! */
			return TRUE;
		}

	} else {
		/* use the absolute value of count */
		count = -count;
	}

	/*
	 * determine test range
	 *
	 * Make sure we have enough odd values to test.
	 */
	if (skip < 0) {
		skip = -skip;	/* use the absolute value of skip */
	}
	skip = (skip<<1) + 3;
	limit = skip + (count<<1);
	if (!zge32b(z)) {
		/* cap limit to odd value < zval */
		if (ztolong(z)-2 < limit) {
			limit = ztolong(z) - 2;
		}
		if (limit <= skip) {
			/* no more odd values to test, so no test failed! */
			return TRUE;
		}
	}

	/*
	 * Loop over various "random" numbers, testing each one.
	 * These numbers are the odd numbers starting from (skip*2)+3
	 */
	zsub(z, _one_, &zm1);
	ik = zlowbit(zm1);
	zshift(zm1, -ik, &z1);
	itoz(skip, &zbase);
	for (base = skip; base < limit; base+=2) {

		/* Knuth Algorithm P */
		ij = 0;
		zpowermod(zbase, z1, z, &z3);
		for (;;) {
			if (zisone(z3)) {
				if (ij)	{
					/* number is definitely not prime */
					zfree(z3);
					zfree(zm1);
					zfree(z1);
					zfree(zbase);
					return FALSE;
				}
				break;
			}
			if (zcmp(z3, zm1) == 0)
				break;
			if (++ij >= ik) {
				/* number is definitely not prime */
				zfree(z3);
				zfree(zm1);
				zfree(z1);
				zfree(zbase);
				return FALSE;
			}
			zsquare(z3, &z2);
			zfree(z3);
			zmod(z2, z, &z3);
			zfree(z2);
		}
		zfree(z3);

		/* quick and dirty zbase+=2 */
		zbase.v[0] += 2;
		if (zbase.v[0] <= 1) {
			/*
			 * carry -- * skip & count are limited to 2^24, and
			 * thus skip+count < 2^31, so we carry at most 1 digit
			 */
			if (zbase.len < 2) {
				zfree(zbase);
				itoz(((FULL)(MAXHALF))+2, &zbase);
			} else {
				zbase.v[0] = 1;
				++zbase.v[1];
			}
		}
	}
	zfree(zm1);
	zfree(z1);
	zfree(zbase);

	/* number might be prime */
	return TRUE;
}


/*
 * znextcand - find the next prime candidate
 *
 * Find the next value that passes ptest().  If modulus != 0,
 * restrict our search to values == modval mod modulus.
 *
 * Returns:
 *	0	prime candidate found
 *	-2	no prime == modval mod modulus exists
 *	-3	invalid modulus
 */
int
znextcand(z, count, skip, modval, modulus, cand)
        ZVALUE z;               /* search point > 2 */
	long count;		/* ptests to perform per candidate */
	long skip;		/* ptests to skip per candidate */
	long modval;		/* modulus!=0 => look for mod modulus==modval */
	long modulus;		/* != 0 => look for mod modulus==modval */
	ZVALUE *cand;		/* candidate found */
{
	unsigned char *jmpp;	/* pointer into jmp for cand */
	short *jmpindx_p;	/* pointer into jmpindx for cand */
	ZVALUE tmp;		/* temp ZVALUE */
	ZVALUE tmp2;		/* temp ZVALUE */
	ZVALUE zmodulus;	/* modulus as a ZVALUE */
	int wasodd;		/* TRUE => original z value was odd */
	long tval;		/* tmp value */

	/*
	 * pre-process modulus if needed
	 */
	modulus = ((modulus == 1) ? 0 : modulus);
	modval = ((modulus == 0) ? 0 : modval);
	if (modulus != 0) {

		/*
		 * XXX - do not handle neg mods, yet
		 */
		if (modulus < 0) {
			/* currently invalid modulus - XXX */
			return -3;
		}

		/*
		 * reduce modval as needed
		 */
		modval %= modulus;

		/*
		 * a modval of 0 implies a multiple and this no primes exist
		 */
		if (modval == 0) {
			/* no such prime exists */
			return -2;
		}
	}

	/*
	 * deal with cases where 2 is the answer
	 */
	if (zisleone(z)) {
		/*
		 * return 2 if it is a valid answer
		 *
		 * This test works because:
		 *
		 * case: modulus == 0
		 * 	 No special modulus form is needed, thus 2 is
		 *	 the next prime.
		 *
		 * case: modval == 2
		 *	 Due to the pre-processing of the modulus, we know
		 *	 that modulus > 2.  Since 2 == 2 mod modulus, 2 is
		 *	 the next prime and is in the form we need.
		 */
		if (modulus == 0 || modval == 2) {
			/* 2 is our next prime */
			itoz(2, cand);
			return 0;
		}

		/* jump forward to 3 */
		itoz(3, &z);
	}

	/*
	 * post-process modulus if needed
	 */
	if (modulus != 0) {

		/*
		 * catch cases where no primes == 'modval' mod 'modulus' exist
		 */
		tval = iigcd(modval, modulus);
		if (tval > 1) {

			/* if beyond the modgcd, then no primes can exist */
			if (zge32b(z) || ztofull(z) >= (FULL)tval) {
				/* no such prime exists */
				return -2;
			}

			/* modgcd could the only prime >= n */
			itoz(tval, &tmp);
			if (zprimetest(tmp, count, skip)) {
				/* return modval % modulus */
				*cand = tmp;
				return 0;
			} else {
				/* no such prime exists */
				zfree(tmp);
				return -2;
			}
		}
	}

	/*
	 * bump to the next odd number
	 */
	if (ziseven(z)) {
		wasodd = FALSE;
		zadd(z, _one_, cand);
	} else {
		wasodd = TRUE;
		zcopy(z, cand);
	}

	/*
	 * if we have a modulus, bump up or down to the next case
	 */
	if (modulus != 0) {
		ZVALUE zmodval;		/* modval as a ZVALUE */
		ZVALUE ztval;		/* temp ZVALUE */

		/* extablish temp values we will use later */
		itoz(modulus, &zmodulus);
		itoz(modval, &zmodval);

		/* bump to the next/prev value == modval mod modulus */
		tval = zmodi(*cand, modulus);
		itoz(tval, &ztval);
		if (tval != modval) {

			/* jump to a point that is == modval mod modulus */
			zsub(*cand, ztval, &tmp);
			zadd(tmp, zmodval, &tmp2);
			zfree(tmp);
			zfree(zmodval);
			zfree(ztval);

			/* if we are the wrong size of or candidate, bump */
			switch (zrel(*cand, tmp2)) {
			case -1:
				zadd(tmp2, zmodulus, cand);
				zfree(tmp2);
				break;
			case 0:
				if (wasodd) {
					zadd(tmp2, zmodulus, cand);
					zfree(tmp2);
				} else {
					zfree(*cand);
					*cand = tmp2;
				}
				break;
			case 1:
				*cand = tmp2;
				break;
			default:
				math_error("zrel returned an strange value!");
				break;
			}

		/* we are on a value == modval mod modulus, so move */
		} else {
			if (wasodd) {
				zadd(*cand, zmodulus, &tmp);
				zfree(*cand);
				*cand = tmp;
			}
			zfree(zmodval);
			zfree(ztval);
		}

		/*
		 * if we are even, bump
		 *
		 * We know that subtracting modulus will bring us to an
		 * odd value because the post-processing of the modulus
		 * assured us that a prime was possible.
		 */
		if (ziseven(*cand)) {
			zadd(*cand, zmodulus, &tmp);
			zfree(*cand);
			*cand = tmp;
		}

		/* skip to next value not divisible by a trivial prime */
		jmpindx_p = &jmpindx[zmodi(*cand,JMPMOD*2) >> 1];
		if (*jmpindx_p > 0) {

			/* jump forward to a jump point */
			zadd(*cand, zconst[*jmpindx_p], &tmp2);
			zfree(*cand);
			*cand = tmp2;

			/* while not at a modval mod modulus, jump forward */
			jmpindx_p = &jmpindx[zmodi(*cand,JMPMOD*2) >> 1];
			jmpp = &jmp[-(*jmpindx_p)];
			while (zmodi(*cand, modulus) != modval) {
				/* jump forward */
				zadd(*cand, zconst[nxtjmp(jmpp)], &tmp2);
				zfree(*cand);
				*cand = tmp2;
			}
			jmpindx_p = &jmpindx[zmodi(*cand,JMPMOD*2)>>1];

		}
		jmpp = &jmp[-(*jmpindx_p)];

	/*
	 * for no modulus, skip to next value not divisible by a trivial prime
	 */
	} else {
		jmpindx_p = &jmpindx[zmodi(*cand,JMPMOD*2) >> 1];
		if (*jmpindx_p > 0) {
			/* not at a jump value, move to next one */
			zadd(*cand, zconst[*jmpindx_p], &tmp2);
			zfree(*cand);
			*cand = tmp2;
			jmpindx_p = &jmpindx[zmodi(*cand,JMPMOD*2)>>1];
		}
		jmpp = &jmp[-(*jmpindx_p)];
	}

	/*
	 * test successive jump values until ptest returns true
	 */
	while (!zprimetest(*cand, count, skip)) {

		/* increment candidate to the next jump point */
		if (modulus != 0) {
			if (modulus < *JPRIME) {
				/*
				 * advance to the next jump point until
				 * we have == modval mod modulus
				 */
				do {
					/* bump */
					zadd(*cand, zconst[nxtjmp(jmpp)], &tmp);
					zfree(*cand);
					*cand = tmp;

					/* if we are even, bump */
					if (ziseven(*cand)) {
						zadd(*cand, zmodulus, &tmp);
						zfree(*cand);
						*cand = tmp;
					}
				} while (zmodi(*cand, modulus) != modval);
			} else {
				/*
				 * advance to next modval mod modulus
				 * we have a jump point
				 */
				do {
					/* bump */
					zadd(*cand, zmodulus, &tmp);
					zfree(*cand);
					*cand = tmp;

					/* if we are even, bump */
					if (ziseven(*cand)) {
						zadd(*cand, zmodulus, &tmp);
						zfree(*cand);
						*cand = tmp;
					}
				} while (zdivides(_jmpmod2_, *cand));
			}
		} else {
			zadd(*cand, zconst[nxtjmp(jmpp)], &tmp2);
			zfree(*cand);
			*cand = tmp2;
		}
	}

	/* return the candidate */
	return 0;
}


/*
 * z0prevcand - find the previous prime candidate
 *
 * Find the previous value that passes ptest().  This function assumes
 * that modulus is 0 and this we will not restrict our previous search.
 *
 * We have two forms of z{0,1}prevcand() because some optimizers choked
 * when they were inline in zprevcand().
 *
 * Returns:
 *	0	prime candidate found
 *	-1	attemtped to find a prime candidate < 2
 *	-2	no prime == modval mod modulus exists
 *	-3	invalid modulus
 */
static int
z0prevcand(z, count, skip, cand)
        ZVALUE z;               /* search point > 2 */
	long count;		/* ptests to perform per candidate */
	long skip;		/* ptests to skip per candidate */
	ZVALUE *cand;		/* candidate found */
{
	unsigned char *jmpp;	/* pointer into jmp for cand */
	short *jmpindx_p;	/* pointer into jmpindx for cand */
	ZVALUE tmp2;		/* temp ZVALUE */
	int wasodd;		/* TRUE => original z value was odd */
	long tval;		/* tmp value */

	/*
	 * bump to the previous odd number
	 */
	if (ziseven(z)) {
		wasodd = FALSE;
		zsub(z, _one_, cand);
	} else {
		wasodd = TRUE;
		zcopy(z, cand);
	}

	/*
	 * for no modulus, skip to prev value not divisible by a trivial prime
	 *
	 * be sure we are at a jump point
	 */
	jmpindx_p = &jmpindx[zmodi(*cand,JMPMOD*2) >> 1];
	if (*jmpindx_p > 0) {
		/* jump forward to the next jump point */
		zadd(*cand, zconst[*jmpindx_p], &tmp2);
		zfree(*cand);

		/* jump back to the previous jump point */
		jmpindx_p = &jmpindx[zmodi(tmp2,JMPMOD*2) >> 1];
		jmpp = &jmp[-(*jmpindx_p)];
		zsub(tmp2, zconst[prevjmp(jmpp)], cand);
		zfree(tmp2);
	} else {
		/* jump back to the previous jump point */
		jmpp = &jmp[-(*jmpindx_p)];
		zsub(*cand, zconst[prevjmp(jmpp)], &tmp2);
		zfree(*cand);
		*cand = tmp2;
	}

	/*
	 * test previous jump values until ptest returns true
	 */
	while (!zprimetest(*cand, count, skip)) {

		/*
		 * decrement candidate to the previous jump point
		 */
		if (zrel(*cand, zconst[*JPRIME]) > 0) {
			zsub(*cand, zconst[prevjmp(jmpp)],
			     &tmp2);
			zfree(*cand);
			*cand = tmp2;
		} else {
			/* the previous prime is the answer */
			tval = zpprime(*cand);
			zfree(*cand);
			itoz(tval, cand);
			return 0;
		}
	}

	/* return the candidate */
	return 0;
}


/*
 * z1prevcand - find the previous prime candidate
 *
 * Find the previous value that passes ptest().  This function assumes
 * that modulus != 0, and thus we restrict our search to the
 * values == modval mod modulus.
 *
 * We have two forms of z{0,1}prevcand() because some optimizers choked
 * when they were inline in zprevcand().
 *
 * Returns:
 *	0	prime candidate found
 *	-1	attemtped to find a prime candidate < 2
 *	-2	no prime == modval mod modulus exists
 *	-3	invalid modulus
 */
static int
z1prevcand(z, count, skip, modval, modulus, cand)
        ZVALUE z;               /* search point > 2 */
	long count;		/* ptests to perform per candidate */
	long skip;		/* ptests to skip per candidate */
	long modval;		/* modulus!=0 => look for mod modulus==modval */
	long modulus;		/* != 0 => look for mod modulus==modval */
	ZVALUE *cand;		/* candidate found */
{
	unsigned char *jmpp;	/* pointer into jmp for cand */
	short *jmpindx_p;	/* pointer into jmpindx for cand */
	ZVALUE tmp;		/* temp ZVALUE */
	ZVALUE tmp2;		/* temp ZVALUE */
	ZVALUE zmodulus;	/* modulus as a ZVALUE */
	ZVALUE zmodval;		/* modval as a ZVALUE */
	ZVALUE ztval;		/* temp ZVALUE */
	int wasodd;		/* TRUE => original z value was odd */
	long tval;		/* tmp value */

	/*
	 * catch cases where no primes == 'modval' mod 'modulus' exist
	 */
	tval = iigcd(modval, modulus);
	if (tval > 1) {

		/* if <= modgcd, then no primes can exist */
		if (!zge32b(z) && ztofull(z) <= (FULL)tval) {
			/* no such prime exists */
			return -2;
		}

		/* modgcd could the only prime < n */
		itoz(tval, &tmp);
		if (zprimetest(tmp, count, skip)) {
			/* return modval % modulus */
			*cand = tmp;
			return 0;
		} else {
			/* no such prime exists */
			zfree(tmp);
			return -2;
		}
	}

	/*
	 * bump to the previous odd number
	 */
	if (ziseven(z)) {
		wasodd = FALSE;
		zsub(z, _one_, cand);
	} else {
		wasodd = TRUE;
		zcopy(z, cand);
	}

	/*
	 * if we have a modulus, bump down to the next case
	 */

	/* extablish temp values we will use later */
	itoz(modulus, &zmodulus);
	itoz(modval, &zmodval);

	/* bump to the prev value == modval mod modulus */
	tval = zmodi(*cand, modulus);
	itoz(tval, &ztval);
	if (tval != modval) {

		/* jump to a point that is == modval mod modulus */
		zsub(*cand, ztval, &tmp);
		zadd(tmp, zmodval, &tmp2);
		zfree(tmp);
		zfree(zmodval);
		zfree(ztval);

		/* if we are the wrong size of or candidate, bump */
		switch (zrel(*cand, tmp2)) {
		case -1:
			*cand = tmp2;
			break;
		case 0:
			if (wasodd) {
				zsub(tmp2, zmodulus, cand);
				zfree(tmp2);
			} else {
				zfree(*cand);
				*cand = tmp2;
			}
			break;
		case 1:
			zsub(tmp2, zmodulus, cand);
			zfree(tmp2);
			break;
		default:
			zfree(*cand);
			zfree(zmodulus);
			math_error("zrel returned a strange value!");
			break;
		}

	/* we are on a value == modval mod modulus, so move */
	} else {
		if (wasodd) {
			zsub(*cand, zmodulus, &tmp);
			zfree(*cand);
			*cand = tmp;
		}
		zfree(zmodval);
		zfree(ztval);
	}

	/* catch the case where 2 is the answer */
	if (zistwo(*cand)) {
		/* the answer is 2 */
		zfree(zmodulus);
		return 0;
	}

	/*
	 * if we are even, bump
	 *
	 * We know that subtracting modulus will bring us to an
	 * odd value because the post-processing of the modulus
	 * assured us that a prime was possible.
	 */
	if (ziseven(*cand)) {
		zsub(*cand, zmodulus, &tmp);
		zfree(*cand);
		*cand = tmp;
	}

	/* watch for < 2 */
	if (zisleone(*cand)) {
		/* no such prime exists */
		zfree(*cand);
		zfree(zmodulus);
		return -2;
	}

	/* skip to prev value not divisible by a trivial prime */
	jmpindx_p = &jmpindx[zmodi(*cand,JMPMOD*2) >> 1];
	if (*jmpindx_p > 0) {

		/* jump back to a jump point */
		zadd(*cand, zconst[*jmpindx_p], &tmp2);
		zfree(*cand);
		jmpindx_p = &jmpindx[zmodi(tmp2,JMPMOD*2) >> 1];
		jmpp = &jmp[-(*jmpindx_p)];
		zsub(tmp2, zconst[prevjmp(jmpp)], cand);
		zfree(tmp2);

		/* while not at a modval mod modulus, jump back */
		while (zmodi(*cand, modulus) != modval) {
			/* jump back */
			if (zrel(*cand, zconst[*JPRIME]) > 0) {
				zsub(*cand, zconst[prevjmp(jmpp)],
				     &tmp2);
				zfree(*cand);
				*cand = tmp2;
			} else {
				/* jump back to a prime, or 0 */
				tval = zpprime(*cand);
				zfree(*cand);
				itoz(tval, cand);

				/* see if we have the answer */
				if (tval >= (FULL)2 &&
				    (long)tval % modulus == modval) {
					/* the prime is the answer */
					zfree(zmodulus);
					return 0;
				}
			}

			/* watch for < 2 */
			if (zisleone(*cand)) {
				/* no such prime exists */
				zfree(*cand);
				zfree(zmodulus);
				return -2;
			}
		}
		jmpindx_p = &jmpindx[zmodi(*cand,JMPMOD*2)>>1];

	}
	jmpp = &jmp[-(*jmpindx_p)];

	/*
	 * test previous jump values until ptest returns true
	 */
	while (!zprimetest(*cand, count, skip)) {

		/*
		 * decrement candidate to the previous jump point
		 */
		if (modulus < *JPRIME) {
			/*
			 * receed to the next jump point until
			 * we have == modval mod modulus
			 */
			do {
				/* jump back */
				if (zrel(*cand, zconst[*JPRIME]) > 0) {
					zsub(*cand,
					     zconst[prevjmp(jmpp)],
					     &tmp2);
					zfree(*cand);
					*cand = tmp2;
				} else {
					/* jump back to a prime, or 0 */
					tval = zpprime(*cand);
					zfree(*cand);
					itoz(tval, cand);

					/* see if we have the answer */
					if (tval >= (FULL)2 &&
					    (long)tval % modulus ==
					    modval) {
						/* prime is answer */
						zfree(zmodulus);
						return 0;
					}
				}

				/* watch for < 2 */
				if (zisleone(*cand)) {
					/* no such prime exists */
					zfree(*cand);
					zfree(zmodulus);
					return -2;
				}
			} while (zmodi(*cand, modulus) != modval);
		} else {
			/*
			 * receed to next modval mod modulus
			 * we have a jump point
			 */
			do {
				/* jump back */
				zsub(*cand, zmodulus, &tmp);
				zfree(*cand);
				*cand = tmp;

				/*
				 * watch for 2 as the answer
				 *
				 * This test works because due to
				 * modulus pre-processing, we know
				 * that modulus > 2 and thus
				 * 2 == 2 mod modulus.
				 */
				if (modval == 2 && zistwo(*cand)) {
					/* the answer is 2 */
					zfree(zmodulus);
					return 0;
				}

				/* if we are even, bump */
				if (ziseven(*cand)) {
					zsub(*cand, zmodulus, &tmp);
					zfree(*cand);
					*cand = tmp;
				}

				/* watch for < 2 */
				if (zisleone(*cand)) {
					/* no such prime exists */
					zfree(*cand);
					zfree(zmodulus);
					return -2;
				}
			} while (zdivides(_jmpmod2_, *cand));
		}
	}

	/* return the candidate */
	return 0;
}


/*
 * zprevcand - find the previous prime candidate
 *
 * Find the previous value that passes ptest().  If modulus != 0,
 * restrict our search to values == modval mod modulus.
 *
 * Returns:
 *	0	prime candidate found
 *	-1	attemtped to find a prime candidate < 2
 *	-2	no prime == modval mod modulus exists
 *	-3	invalid modulus
 */
int
zprevcand(z, count, skip, modval, modulus, cand)
        ZVALUE z;               /* search point > 2 */
	long count;		/* ptests to perform per candidate */
	long skip;		/* ptests to skip per candidate */
	long modval;		/* modulus!=0 => look for mod modulus==modval */
	long modulus;		/* != 0 => look for mod modulus==modval */
	ZVALUE *cand;		/* candidate found */
{
	/*
	 * pre-process modulus if needed
	 */
	modulus = ((modulus == 1) ? 0 : modulus);
	modval = ((modulus == 0) ? 0 : modval);
	if (modulus != 0) {

		/*
		 * XXX - we do not handle neg mods, yet
		 */
		if (modulus < 0) {
			/* currently invalid modulus - XXX */
			return -3;
		}

		/*
		 * reduce modval as needed
		 */
		modval %= modulus;

		/*
		 * a modval of 0 implies a multiple and this no primes exist
		 */
		if (modval == 0) {
			/* no such prime exists */
			return -2;
		}
	}

	/*
	 * deal with z <= 2
	 */
	/* catch with too small of a level */
	if (zisleone(z) || zistwo(z)) {
		/* attemtped to find a prime candidate < 2 */
		return -1;
	}

	/*
	 * We will call z0prevcand() or z1prevcand() depending on
	 * the value of modulus.  We do this because if we combine
	 * the two functions inline, some optimizers choke.
	 */
	if (modulus == 0) {
		return z0prevcand(z, count, skip, cand);
	} else {
		return z1prevcand(z, count, skip, modval, modulus, cand);
	}
}


/*
 * Find the lowest prime factor of a number if one can be found.
 * Search is conducted for the first count primes.
 *
 * Returns:
 *	1	no factor found or z < 3
 *	>1	factor found
 */
FULL
zlowfactor(z, count)
	ZVALUE z;
	long count;
{
	FULL factlim;		/* highest factor to test */
	unsigned short *p;	/* test factor */
	FULL factor;		/* test factor */
	HALF tlim;		/* limit on prime table use */
	HALF divval[2];		/* divisor value */
	ZVALUE div;		/* test factor/divisor */
	ZVALUE tmp;

	/*
	 * firewall
	 */
	if (count <= 0 || zisleone(z) || zistwo(z)) {
		/* number is < 3 or count is <= 0 */
		return (FULL)1;
	}

	/*
	 * test for the first factor
	 */
	if (ziseven(z)) {
		return (FULL)2;
	}
	if (count <= 1) {
		/* count was 1, tested the one and only factor */
		return (FULL)1;
	}

	/*
	 * determine if/what our sqrt factor limit will be
	 */
	if (zge64b(z)) {
		/* we have no factor limit, avoid highest factor */
		factlim = MAX_SM_PRIME-1;
	} else if (zge32b(z)) {
		/* find the isqrt(z) */
		if (zsqrt(z, &tmp)) {
			/* sqrt is exact */
			factlim = ztofull(tmp);
		} else {
			/* sqrt is inexact */
			factlim = ztofull(tmp)+1;
		}
		zfree(tmp);

		/* avoid highest factor */
		if (factlim >= MAX_SM_PRIME) {
			factlim = MAX_SM_PRIME-1;
		}
	} else {
		/* determine our factor limit */
		factlim = fsqrt(ztofull(z));
	}
	if (factlim >= MAX_SM_PRIME) {
		factlim = MAX_SM_PRIME-1;
	}

	/*
	 * walk the prime table looking for factors
	 */
	tlim = (HALF)((factlim >= MAX_MAP_PRIME) ? MAX_MAP_PRIME-1 : factlim);
	div.sign = 0;
	div.v = divval;
	div.len = 1;
	for (p=prime, --count; count > 0 && (HALF)*p <= tlim; ++p, --count) {

		/* setup factor */
		div.v[0] = (HALF)(*p);

		/* divide */
		zmod(z, div, &tmp);

		/* check if we have a remainder */
		if (ziszero(tmp)) {
			/* p is a factor */
			zfree(tmp);
			return (FULL)(*p);
		}
		zfree(tmp);
	}
	if (count <= 0 || (FULL)*p > factlim) {
		/* no factor found */
		return (FULL)1;
	}

	/*
	 * test the highest factor possible
	 */
	div.v[0] = MAX_MAP_PRIME;
	/* divide */
	zmod(z, div, &tmp);
	/* check if we have a remainder */
	if (ziszero(tmp)) {
		/* factor is found */
		zfree(tmp);
		return (FULL)MAX_MAP_PRIME;
	}
	zfree(tmp);

	/*
	 * generate higher test factors as needed
	 */
#if BASEB == 16
	div.len = 2;
#endif
	for(factor = NXT_MAP_PRIME;
	    count > 0 && factor <= factlim;
	    factor = next_prime(factor), --count) {

		/* setup factor */
#if BASEB == 32
		div.v[0] = factor;
#else
		div.v[0] = (factor & BASE1);
		div.v[1] = (factor >> BASEB);
#endif

		/* divide */
		zmod(z, div, &tmp);

		/* check if we have a remainder */
		if (ziszero(tmp)) {
			/* factor is found */
			zfree(tmp);
			return (FULL)(factor);
		}
		zfree(tmp);
	}
	if (count <= 0 || factor >= factlim) {
		/* no factor found */
		return (FULL)1;
	}

	/*
	 * test the highest factor possible
	 */
#if BASEB == 32
	div.v[0] = MAX_SM_PRIME;
#else
	div.v[0] = (MAX_SM_PRIME & BASE1);
	div.v[1] = (MAX_SM_PRIME >> BASEB);
#endif
	/* divide */
	zmod(z, div, &tmp);
	/* check if we have a remainder */
	if (ziszero(tmp)) {
		/* factor is found */
		zfree(tmp);
		return (FULL)MAX_SM_PRIME;
	}
	zfree(tmp);

	/*
	 * no factor found
	 */
	return (FULL)1;
}


/*
 * Compute the least common multiple of all the numbers up to the
 * specified number.
 */
void
zlcmfact(z, dest)
	ZVALUE z, *dest;
{
	long n;			/* limiting number to multiply by */
	long p;			/* current prime */
	long pp = 0;		/* power of prime */
	long i;			/* test value */
	unsigned short *pr;	/* pointer to a small prime */
	ZVALUE res, temp;

	if (zisneg(z) || ziszero(z))
		math_error("Non-positive argument for lcmfact");
	if (zge24b(z))
		math_error("Very large lcmfact");
	n = ztolong(z);
	/*
	 * Multiply by powers of the necessary odd primes in order.
	 * The power for each prime is the highest one which is not
	 * more than the specified number.
	 */
	res = _one_;
	for (pr=prime; *pr <= n && *pr > 1; ++pr) {
		i = p = *pr;
		while (i <= n) {
			pp = i;
			i *= p;
		}
		zmuli(res, pp, &temp);
		zfree(res);
		res = temp;
	}
	for (p = NXT_MAP_PRIME; p <= n; p = next_prime(p)) {
		i = p;
		while (i <= n) {
			pp = i;
			i *= p;
		}
		zmuli(res, pp, &temp);
		zfree(res);
		res = temp;
	}
	/*
	 * Finish by scaling by the necessary power of two.
	 */
	zshift(res, zhighbit(z), dest);
	zfree(res);
}


/*
 * fsqrt - fast square root of a FULL value
 *
 * We will determine the square root of a given value.
 * Starting with the integer square root of the largest power of
 * two <= the value, we will perform 3 Newton interations to
 * arive at our guess.
 *
 * We have verified that fsqrt(x) == (FULL)sqrt((double)x), or
 * fsqrt(x)-1 == (FULL)sqrt((double)x) for all 0 <= x < 2^32.
 */
static FULL
fsqrt(x)
    FULL x;		/* compute the integer square root of x */
{
    FULL y;		/* (FULL)temporary value */
    int i;

    /* firewall - deal with 0 */
    if (x == 0) {
	return 0;
    }

    /* ignore Saber-C warning #530 about empty for statement */
    /*	  ok to ignore in proc fsqrt */
    /* determine our initial guess */
    for (i=0, y=x; y >= (FULL)256; i+=8, y>>=8) {
    }
    y = isqrt_pow2[i + topbit[y]];

    /* perform 3 Newton interations */
    y = (y+x/y)>>1;
    y = (y+x/y)>>1;
    y = (y+x/y)>>1;
#if FULL_BITS == 64
    y = (y+x/y)>>1;
#endif

    /* return the result */
    return y;
}
