www.pudn.com > calc.rar > primes1.c


/* primes1.c */ 
#include  
#include  
#include  
#include "integer.h" 
#include "fun.h" 
#include "bigprime.h" 
#ifdef _WIN32 
#include "unistd_DOS.h" 
#else 
#include  
#endif 
 
 
extern unsigned long PRIME[]; 
extern unsigned int reciprocal[][Z0]; 
extern unsigned int VERBOSE; 
extern unsigned int FREE_PRIMES;/* FREE_PRIMES = 1 destroys the Q_[i] below */ 
extern unsigned int ECMAX; 
#define JMAX 500 
 
 
MPI *PERFECT_POWER(MPI *N) 
/* 
 * Here N > 1. 
 * Returns X if N = X^k, for some X, k > 1,  NULL otherwise. 
 * See E. Bach and J. Sorenson, "Sieve algorithms for perfect power testing" 
 * Algorithmica 9 (1993) 313-328. 
 */ 
{ 
	unsigned int i, t; 
	int s; 
	MPI *X, *Y; 
 
	t = BINARYB(N)-1; 
	i = 0; 
	while (PRIME[i] <= t) 
	{ 
		X = BIG_MTHROOT(N, (USI) PRIME[i]); 
		Y = POWERI(X, (USI) PRIME[i]); 
		s = RSV(Y, N); 
		FREEMPI(Y); 
		if (s == 0) 
			return (X); 
		else 
		{ 
			i++; 
			FREEMPI(X); 
		} 
	} 
	return ((MPI *) NULL); 
} 
 
MPI *POLLARD(MPI *Nptr) 
/*  
 * Pollard's p-1 method of factoring *Nptr. 
 */ 
{ 
	unsigned long i, b = 1; 
	MPI *T, *P, *TT, *TMP, *PP; 
	 
	PP = ONEI(); 
	T = ADD0I(PP, PP); 
	while (b <= 2){ 
		b++; 
		printf("b = %lu\n", b); 
		i = 2; 
	while (i  <= 10000) 
	{ 
		if (i % 100 == 0)	 
			printf("i = %lu\n", i); 
		TMP = T; 
		T = MPOWER_M(T, i, Nptr); 
		FREEMPI(TMP); 
		TT = SUB0I(T, PP); 
		P = GCD(Nptr, TT); 
		FREEMPI(TT); 
		if (!EQONEI(P) && RSV(P, Nptr) == -1) 
		{ 
			PRINTI(P); 
			printf(" is a proper factor of "); 
			PRINTI(Nptr); 
			printf("\n"); 
			FREEMPI(PP); 
			FREEMPI(T); 
			return (P); 
		} 
		if (EQUALI(P, Nptr)) 
		{ 
			FREEMPI(P); 
			b++; 
			TMP = T; 
			printf("GCD = *Nptr; b increased to %lu\n", b); 
			T = CHANGE(b); 
			FREEMPI(TMP); 
			continue; 
		} 
		FREEMPI(P); 
		i++; 
	} 
} 
	printf("no factors returned\n"); 
	FREEMPI(PP); 
	FREEMPI(T); 
	return ((MPI *)NULL); 
} 
 
MPI *BRENT_POLLARD(MPI *Nptr) 
/* 
 * the Brent-Pollard method for returning a proper factor of 
 * a composite MPI *Nptr. (see R. Brent, BIT 20, 176 - 184). 
 */ 
{ 
	MPI  *X, *Y, *Z, *Temp, *Gptr, *PRODUCT, *Temp1; 
	unsigned int g, k; 
	unsigned long a, r, i, s, t; 
	 
	if (VERBOSE) 
	{ 
		printf("BRENT-POLLARD IS SEARCHING FOR A PROPER FACTOR OF "); 
		PRINTI(Nptr); 
		printf("\n"); 
	} 
	a = 1; 
	g = 1; 
	r = 1; 
	PRODUCT = ONEI(); 
	Gptr = ONEI(); 
	Y = ZEROI(); 
	while (g == 1) 
	{ 
		X = COPYI(Y); 
		for (i = 1; i <= r; i++) 
		{ 
			Temp = Y; 
			Y = MPOWER_M(Y, (USL)2, Nptr); 
			FREEMPI(Temp); 
			Temp = Y; 
			Y = ADD0_I(Y, a); 
			FREEMPI(Temp); 
			Temp = Y; 
			Y = MOD0(Y, Nptr); 
			FREEMPI(Temp); 
		} 
		k = 0; 
		while (1) 
		{ 
			Temp = Y; 
			Y = MULTI(Y, Y); 
			FREEMPI(Temp); 
			Temp = Y; 
			Y = ADD0_I(Y, a); 
			FREEMPI(Temp); 
			Temp = Y; 
			Y = MOD0(Y, Nptr); 
			FREEMPI(Temp); 
			k++; 
			Z = SUBI(X, Y); 
			Temp1 = PRODUCT; 
			PRODUCT = MULTI(PRODUCT, Z); 
			FREEMPI(Z); 
			FREEMPI(Temp1); 
			if (k % 10 == 0) 
			{ 
				FREEMPI(Gptr); 
				Gptr = GCD(PRODUCT, Nptr); 
				FREEMPI(PRODUCT); 
				PRODUCT = ONEI(); 
				if (Gptr->D || Gptr->V[0] > 1) 
				{ 
					g = 0; 
					break; 
				} 
			} 
			if (k >= r) 
				break; 
		} 
		FREEMPI(X); 
		r = 2 * r; 
		if (VERBOSE) 
			printf("r = %lu\n", r); 
		s = r & 8192; 
		t = EQUALI(Gptr, Nptr); 
		if (s || t) 
		{ 
			g = 1; 
			if (t) 
			{ 
				a++; 
				if (VERBOSE) 
					printf("a increased to %lu\n", a); 
			} 
 			FREEMPI(Gptr); 
                        Gptr = ONEI(); 
			r = 1; 
			FREEMPI(Y); 
			Y = ZEROI(); 
			if (s || (a == 3)) 
			{ 
				if (VERBOSE) 
				{ 
					printf(" BRENT_POLLARD failed to find a factor of "); 
					PRINTI(Nptr); 
					printf("\n"); 
				} 
				FREEMPI(Gptr); 
				FREEMPI(PRODUCT); 
				FREEMPI(Y); 
				return ((MPI *) NULL); 
			} 
		} 
/* 
		if (g) 
			FREEMPI(Gptr); 
*/ 
	} 
	FREEMPI(Y); 
	if (VERBOSE) 
	{ 
		printf("--\n"); 
		printf("BRENT_POLLARD FINISHED: \n"); 
		PRINTI(Gptr); 
		printf(" IS A PROPER FACTOR OF "); 
		PRINTI(Nptr); 
		printf("--\n"); 
	} 
	FREEMPI(PRODUCT); 
	return (Gptr); 
} 
 
unsigned long Q[JMAX]; 
unsigned int j, j_, K[JMAX], K_[JMAX], ltotal; 
MPI *Q_[JMAX], *Q_PRIME[JMAX]; 
 
MPI *BABY_DIVIDE(MPI *Nptr) 
/* 
 * *Eptr = 1 if *Nptr is composed of primes < 1000, otherwise *Eptr 
 * is the part of *Nptr composed of primes > 1000, 
 * The prime factors of *Nptr < 1000 are stored in the global array Q[] 
 * and the corresponding exponents in the global array K[]. 
 */ 
{ 
	MPI *X, *Temp; 
	unsigned int a = Y0, i, k; 
	unsigned long y; 
 
	X = COPYI(Nptr); 
	for (i = 0; i < a; i++) 
	{ 
		k = 0; 
		y = MOD0_(X, PRIME[i]); 
		if (y == 0) 
		{ 
 			while (y == 0) 
			{ 
				k++; 
				Temp = X; 
				X = INT0_(X, PRIME[i]); 
				FREEMPI(Temp); 
				y = MOD0_(X, PRIME[i]); 
			} 
			Q[j] = PRIME[i]; 
			K[j] = k; 
			j++; 
			if (j == JMAX) 
				execerror("j = JMAX, increase JMAX", ""); 
			if(VERBOSE){ 
				printf("%lu is a prime factor of ", PRIME[i]); 
				PRINTI(Nptr); 
				printf(" exponent: %u\n", k); 
				printf("--\n"); 
			} 
		} 
	} 
	return (X); 
} 
 
unsigned int MILLER(MPI *Nptr, USL b) 
/* 
 * *Nptr is odd, > 1, and does not divide b, 0 < b < R0. 
 *  if 1 is returned, then *Nptr passes Miller's test for base b. 
 * if 0 is returned, then *Nptr is composite. 
 */ 
{ 
	MPI *A, *C, *D, *Temp; 
	unsigned int i = 0, j = 0; 
 
	D = SUB0_I(Nptr, (USL)1); 
	A = INT0_(D, (USL)2); 
	while (MOD0_(A, (USL)2) == 0) 
	{ 
		i++; 
		Temp = A; 
		A = INT0_(A, (USL)2); 
		FREEMPI(Temp); 
	} 
	C = MPOWER_((long)b, A, Nptr); 
	if (C->D == 0 && C->V[0] == 1)  
	{ 
		FREEMPI(C); 
		FREEMPI(D); 
		FREEMPI(A); 
		return (1); 
	} 
	while (1) 
	{ 
		if (EQUALI(C, D)) 
		{ 
			FREEMPI(C); 
			FREEMPI(D); 
			FREEMPI(A); 
			return (1); 
		} 
		j++; 
		if (i < j) 
		{ 
			FREEMPI(C); 
			FREEMPI(D); 
			FREEMPI(A); 
			return (0); 
		} 
		Temp = C; 
		C = MULTI(C, C); 
		FREEMPI(Temp); 
		Temp = C; 
		C = MOD0(C, Nptr); 
		FREEMPI(Temp); 
		Temp = A; 
		A = MULT_I(A, 2L); 
		FREEMPI(Temp); 
	} 
} 
 
unsigned int Q_PRIME_TEST(MPI *Nptr) 
/* 
 * *Nptr > 1 and not equal to PRIME[0],...,PRIME[4]. 
 * if 1 is returned, then *Nptr passes Miller's test for bases PRIME[0], 
 * ...,PRIME[4] and is likely to be prime. 
 * if 0 is returned, then *Nptr is composite. 
 */ 
{ 
	unsigned int i; 
 
	for (i = 0; i <= 4; i++) 
	{ 
		if (MILLER(Nptr, PRIME[i]) == 0) 
		{ 
			if (VERBOSE) 
			{ 
				printf("MILLER'S TEST FINISHED: \n"); 
				PRINTI(Nptr); 
				printf(" is composite \n"); 
				printf("--\n"); 
			} 
			return (0); 
		} 
	} 
	if (VERBOSE) 
	{ 
		PRINTI(Nptr); 
		printf(" passed MILLER'S TEST\n"); 
		printf("--\n"); 
	} 
	return (1); 
	 
} 
 
MPI *BIG_FACTOR(MPI *Nptr) 
/* 
 * *Nptr > 1 is not divisible by PRIMES[0], ..., PRIMES[167]. 
 * BIG_FACTOR returns a factor *Eptr > 1000 of *Nptr which is either  
 * < 1,000,000 (and hence prime) or which passes Miller's test for bases  
 * PRIMES[0],...,PRIMES[4] and is therefore likely to be prime. 
 */ 
{ 
	MPI *B, *X, *Y, *Temp; 
	unsigned int f; 
 
	B = BUILDMPI(2);	 
	B->V[0] = 16960; 
	B->V[1] = 15; 
	B->S = 1; /* *B = 1,000,000. */ 
 
	if (RSV(Nptr, B) == -1 || Q_PRIME_TEST(Nptr)) 
	{ 
		FREEMPI(B); 
		return (COPYI(Nptr)); 
	} 
	f = 1; 
	X = COPYI(Nptr); 
	while (f) 
	{ 
		Y = BRENT_POLLARD(X); 
		if (Y == NULL) 
			Y = PERFECT_POWER(X); 
		if (Y == NULL) 
			Y = MPQS1(X); 
		if (Y == NULL) 
		{ 
			printf("Switching to ECF:%u elliptic curves\n", ECMAX); 
			Y = EFACTOR(X,1279,1); 
		} 
		if (Y == NULL) 
		{ 
			printf("Switching to POLLARD p-1\n"); 
			Y = POLLARD(X); 
		} 
		if (Y == NULL) 
			execerror("no factor found", ""); 
		Temp = X; 
		X = INT0(X, Y); 
		FREEMPI(Temp); 
		if (RSV(X, Y) == 1) 
		{ 
			Temp = X; 
			X = COPYI(Y);  
			FREEMPI(Temp); 
		} 
		if (RSV(X, B) == -1) 
		{ 
			FREEMPI(B); 
			FREEMPI(Y); 
			return (X); 
		} 
		if (Q_PRIME_TEST(X)) 
			f = 0; 
		FREEMPI(Y); 
	} 
	FREEMPI(B); 
	return (X); 
} 
 
unsigned int PRIME_FACTORS(MPI *Nptr) 
/* 
 * A quasi-prime (q-prime) factor of *Nptr is > 1,000,000, 
 * is not divisible by PRIMES[0],...,PRIMES[167], passes Millers' test 
 * for bases PRIMES[0],...,PRIMES[10] and is hence likely to be prime. 
 * PRIME_FACTORS returns the number of q-prime factors of *Nptr, stores 
 * them in the global array Q_PRIME[]. 
 * Any prime factors < 1000 of *Nptr and corresponding exponents  
 * are printed and placed in the arrays Q[] and K[], while any prime factors 
 * > 1000 and all q-prime factors and corresponding exponents of *Nptr are  
 * printed and placed in the arrays Q_[] and K_[]. 
 */ 
{ 
	MPI *B, *P, *X, *Z, *Temp; 
	unsigned int k, t; 
 
	B = BUILDMPI(2);	 
	B->V[0] = 16960; 
	B->V[1] = 15; 
	B->S = 1; 
	if (VERBOSE) 
	{ 
		printf("FACTORIZING "); 
		PRINTI(Nptr); 
		printf("--\n"); 
	} 
	X = BABY_DIVIDE(Nptr); 
	t = ltotal; 
	while (X->D || X->V[0] != 1) 
	{ 
		k = 0; 
		P = BIG_FACTOR(X); 
		while (1) 
		{ 
			Z = MOD0(X, P); 
			if (Z->S != 0) 
			{ 
				FREEMPI(Z); 
				break; 
			} 
			FREEMPI(Z); 
			k++; 
			Temp = X; 
			X = INT0(X, P); 
			FREEMPI(Temp); 
		}		 
		if (VERBOSE) 
		{ 
			if (RSV(P, B) == -1) 
			{ 
				PRINTI(P); 
				printf(" is a prime factor of "); 
				PRINTI(Nptr); 
				printf("\n"); 
			} 
		} 
		if (RSV(P, B) == 1) 
		{ 
			if (VERBOSE) 
			{ 
				PRINTI(P); 
				printf(" is a q-prime factor of "); 
				PRINTI(Nptr); 
				printf("\n"); 
			} 
			Q_PRIME[ltotal] = COPYI(P); 
			ltotal++; 
		} 
		Q_[j_] = COPYI(P); 
		FREEMPI(P); 
		K_[j_] = k; 
		j_++; 
		if (j_ == JMAX) 
			execerror("j_ = JMAX, increase JMAX", ""); 
		if (VERBOSE) 
		{ 
			printf(" exponent: %u\n", k); 
			printf("--\n"); 
		} 
	} 
	if (VERBOSE) 
	{ 
		printf("FACTORIZATION INTO PRIMES AND Q-PRIMES COMPLETED FOR "); 
		PRINTI(Nptr); 
		printf("\n------------------------------------\n"); 
	} 
	FREEMPI(B); 
	FREEMPI(X); 
	return (ltotal - t); 
} 
 
unsigned int SELFRIDGE(MPI *Nptr, USI *uptr) 
/* 
 * Selfridges's test for primality - see "Prime Numbers and Computer 
 * Methods for Factorization" by H. Riesel, Theorem 4.4, p.106.  
 * *Nptr > 1 is a q-prime. 
 * The prime and q-prime factors of n - 1 are first found. If no q-prime 
 * factor is present and 1 is returned, then n is prime. However if at 
 * least one q-prime factor is present and 1 is returned, then n retains its 
 * q-prime status. If 0 is returned, then n is either composite or likely  
 * to be composite. 
 */ 
{ 
	MPI *S, *T, *M, *N; 
	unsigned int i, i_; 
	unsigned long x; 
 
	i = j; 
	i_ = j_; 
	M = SUB0_I(Nptr, (USL)1); 
	if (VERBOSE) 
	{ 
		printf("SELFRIDGE'S EXPONENT TEST IN PROGRESS FOR "); 
		PRINTI(Nptr); 
		printf("\n"); 
	} 
	*uptr = PRIME_FACTORS(M); 
	while (i <= j - 1) 
	{ 
		for (x = 2; x < (USL)R0; x++) 
		{ 
			S = MPOWER_((long)x, M, Nptr); 
			if (S->D || S->V[0] != 1) 
			{ 
				if (VERBOSE) 
				{ 
				printf("SELFRIDGE'S TEST IS FINISHED:\n"); 
				PRINTI(Nptr);         
				printf(" is not a pseudo-prime to base %lu\n", x); 
				printf(" and is hence composite\n"); 
				} 
				FREEMPI(S); 
				FREEMPI(M); 
				return (0); 
			} 
			FREEMPI(S); 
			N = INT0_(M, Q[i]); 
			T = MPOWER_((long)x, N, Nptr); 
			FREEMPI(N); 
			if (T->D || T->V[0] != 1) 
			{ 
				i++; 
				FREEMPI(T); 
				break; 
			} 
			FREEMPI(T); 
		} 
		if (x == R0) 
		{ 
			if (VERBOSE) 
			{ 
				printf("SELFRIDGE'S TEST IS FINISHED:\n"); 
				PRINTI(Nptr); 
				printf(" is likely to be composite\n"); 
			} 
			FREEMPI(M); 
			return (0);  
		} 
	} 
	while (i_ <= j_ - 1) 
	{ 
		for (x = 2; x < (USL)R0; x++) 
		{ 
			S = MPOWER_((long)x, M, Nptr); 
			if (S->D || S->V[0] != 1) 
			{ 
				if (VERBOSE) 
				{ 
				printf("SELFRIDGE'S TEST IS FINISHED:\n"); 
				PRINTI(Nptr);         
				printf(" is not a pseudo-prime to base %lu\n", x); 
				printf(" and is hence composite\n"); 
				} 
				FREEMPI(M); 
				FREEMPI(S); 
				return (0); 
			} 
			FREEMPI(S); 
			N = INT0(M, Q_[i_]); 
			T = MPOWER_((long)x, N, Nptr); 
			FREEMPI(N); 
			if (T->D || T->V[0] != 1) 
			{ 
				i_++; 
				FREEMPI(T); 
				break; 
			} 
			FREEMPI(T); 
		} 
		if (x == R0) 
		{ 
			if (VERBOSE) 
				printf("SELFRIDGE'S TEST IS INCONCLUSIVE:\n"); 
			FREEMPI(M); 
			return (0);  
		} 
	} 
	FREEMPI(M); 
	if (*uptr == 0) 
	{ 
		if (VERBOSE) 
		{ 
			printf("SELFRIDGE'S TEST IS FINISHED:\n"); 
			PRINTI(Nptr); 
			printf(" is prime\n"); 
			printf("--\n"); 
		} 
		return (1); 
	} 
	else 
	{ 
		if (VERBOSE) 
		{ 
			printf("SELFRIDGE'S TEST IS FINISHED:\n"); 
			PRINTI(Nptr); 
			printf(" retains its q-prime status\n"); 
			printf("--\n"); 
		} 
		return (1); 
	} 
} 
 
unsigned int scount; /* the number of prime factors of N < 1000 */ 
unsigned int s_count; /* the number of q-prime factors of N */ 
 
unsigned int FACTOR(MPI *Nptr) 
/* 
 * a factorization of *Nptr into prime and q-prime factors is first obtained. 
 * Selfridge's primality test is then applied to any q-prime factors; the test  
 * is applied repeatedly until either a q-prime is found to be composite or 
 * likely to be composite (in which case the initial factorization is doubtful  
 * and an extra base should be used in Miller's test) or we run out of q-primes, 
 * in which case every q-prime factor of *Nptr is certified as prime. 
 */ 
{ 
	unsigned int c, i, t, u, r, count; 
 
	j = j_ = ltotal = 0; 
	c = PRIME_FACTORS(Nptr); 
	scount = j; 
	s_count = j_; 
	if (c == 0) 
	{ 
		if (VERBOSE) 
		{ 
			printf("NO Q-PRIMES:\n\n"); 
			PRINTI(Nptr); 
			printf(" has the following factorization:\n\n"); 
			for (i = 0; i < scount; i++) 
				printf("prime factor: %lu exponent: %u\n", Q[i], K[i]); 
			for (i = 0; i < s_count; i++) 
			{ 
				printf("prime factor: "); 
				PRINTI(Q_[i]); 
				printf(" exponent: %u\n", K_[i]); 
			} 
		} 
		count = scount + s_count; 
	} 
	else 
	{ 
		if (VERBOSE) 
		{ 
			printf("TESTING Q-PRIMES FOR PRIMALITY\n"); 
			printf("--\n"); 
		} 
		i = 0; 
		while (c) 
		{ 
			t = SELFRIDGE(Q_PRIME[i], &u); 
			FREEMPI(Q_PRIME[i]); 
			if (t == 0) 
			{ 
				printf("do FACTOR() again with an extra base\n"); 
				for (r = i + 1; r < ltotal; r++) 
					FREEMPI(Q_PRIME[r]); 
				for (i = 0; i < j_; i++) 
					FREEMPI(Q_[i]); 
				return (0); 
			}		 
			c = c + u; 
			i++; 
			c--; 
		} 
		if (VERBOSE) 
		{ 
			printf("ALL Q-PRIMES ARE PRIMES:\n\n"); 
			PRINTI(Nptr); 
			printf(" has the following factorization:\n\n"); 
			for (i = 0; i < scount; i++) 
				printf("prime factor: %lu exponent: %u\n", Q[i], K[i]); 
			for (i = 0; i < s_count; i++) 
			{ 
				printf("prime factor: "); 
				PRINTI(Q_[i]); 
				printf(" exponent: %u\n", K_[i]); 
			} 
		} 
		count = scount + s_count; 
	} 
	/*printf("s_count = %u, j_ = %u\n", s_count, j_);*/ 
	for (i = s_count; i < j_; i++) 
		FREEMPI(Q_[i]); 
	if (FREE_PRIMES) 
	{ 
		for (i = 0; i < s_count; i++) 
			FREEMPI(Q_[i]); 
	} 
	return (count); 
} 
 
MPI *DIVISOR(MPI *N) 
/* 
 *  Returns the number of divisors of N, 
 *  returns NULL if factorization unsuccessful . 
 */ 
{ 
	MPI *U, *Tmp; 
	unsigned int i, s; 
 
	if (EQONEI(N)) 
		return (ONEI()); 
	U = ONEI(); 
	FREE_PRIMES = 1; /* This frees the Q_[i] in FACTOR()*/ 
	s = FACTOR(N); 
	FREE_PRIMES = 0;  
	if (s == 0) 
	{ 
		FREEMPI(U); 
		return ((MPI *)NULL); 
	} 
	for (i = 0; i < scount; i++) 
	{ 
		Tmp = U; 
		U = MULT_I(U, 1 + (USL)K[i]); 
		FREEMPI(Tmp); 
	} 
	for (i = 0; i < s_count; i++) 
	{ 
		Tmp = U; 
		U = MULT_I(U, 1 + (USL)K_[i]); 
		FREEMPI(Tmp); 
	} 
	return (U); 
} 
 
MPI *MOBIUS(MPI *N) 
/* 
 *  Returns the Mobius function mu(N), 
 *  returns NULL if factorization unsuccessful . 
 */ 
{ 
	MPI *S; 
	unsigned int i, s; 
 
	if (EQONEI(N)) 
		return (ONEI()); 
	FREE_PRIMES = 1; /* This frees the Q_[i] in FACTOR()*/ 
	s = FACTOR(N); 
	FREE_PRIMES = 0;  
	if (s == 0) 
		return ((MPI *)NULL); 
	for (i = 0; i < scount; i++) 
		if (K[i] >= 2) 
			return (ZEROI()); 
	for (i = 0; i < s_count; i++) 
	{ 
		if (K_[i] >= 2) 
			return (ZEROI()); 
	} 
	if (s % 2) 
		return (MINUS_ONEI()); 
	else 
		return (ONEI()); 
	return (S); 
} 
 
MPI *EULER(MPI *N) 
/* 
 *  Returns Euler's function  phi(N), 
 *  returns NULL if factorization unsuccessful . 
 */ 
{ 
	MPI *U, *V, *W, *Tmp; 
	unsigned int i, s; 
 
	if (EQONEI(N)) 
		return (ONEI()); 
	U = ONEI(); 
	/* FREE_PRIMES = 0, so we can free the Q_[i] later */  
	s = FACTOR(N); 
	if (s == 0) 
	{ 
		FREEMPI(U); 
		return ((MPI *)NULL); 
	} 
	for (i = 0; i < scount; i++) 
	{ 
		if (K[i] == 1) 
			V = ONEI(); 
		else 
			V = POWER_I((long)(Q[i]), K[i] - 1); 
		W = CHANGE(Q[i] - 1); 
		Tmp = U; 
		U = MULTI3(U, V, W); 
		FREEMPI(Tmp); 
		FREEMPI(V); 
		FREEMPI(W); 
	} 
	for (i = 0; i < s_count; i++) 
	{ 
		if (K_[i] == 1) 
			V = ONEI(); 
		else 
			V = POWERI(Q_[i], K_[i] - 1); 
		W = SUB0_I(Q_[i], 1); 
		Tmp = U; 
		U = MULTI3(U, V, W); 
		FREEMPI(Tmp); 
		FREEMPI(V); 
		FREEMPI(W); 
	} 
	for (i = 0; i < s_count; i++) 
		FREEMPI(Q_[i]); 
	return (U); 
} 
 
MPI *SIGMA(MPI *N) 
/* 
 *  Returns sigma(N), the sum of the divisors of N, 
 *  returns NULL if factorization unsuccessful . 
 */ 
{ 
	MPI *U, *V, *W, *Tmp; 
	unsigned int i, s; 
 
	if (EQONEI(N)) 
		return (ONEI()); 
	U = ONEI(); 
	/* FREE_PRIMES = 0, so we can free the Q_[i] later */  
	s = FACTOR(N); 
	if (s == 0) 
	{ 
		FREEMPI(U); 
		return ((MPI *)NULL); 
	} 
	for (i = 0; i < scount; i++) 
	{ 
		V = POWER_I((long)(Q[i]), K[i] + 1); 
		Tmp = V; 
		V = SUB0_I(V, 1); 
		FREEMPI(Tmp); 
		Tmp = V; 
		V = INT0_(V, Q[i] - 1); 
		FREEMPI(Tmp); 
		Tmp = U; 
		U = MULTI(U, V); 
		FREEMPI(Tmp); 
		FREEMPI(V); 
	} 
	for (i = 0; i < s_count; i++) 
	{	V = POWERI(Q_[i], K_[i] + 1); 
		Tmp = V; 
		V = SUB0_I(V, 1); 
		FREEMPI(Tmp); 
		Tmp = V; 
		W = SUB0_I(Q_[i], 1); 
		V = INT0(V, W); 
		FREEMPI(W); 
		FREEMPI(Tmp); 
		Tmp = U; 
		U = MULTI(U, V); 
		FREEMPI(Tmp); 
		FREEMPI(V); 
	} 
	for (i = 0; i < s_count; i++) 
		FREEMPI(Q_[i]); 
	return (U); 
} 
 
MPI *LPRIMROOT(MPI *P) 
/* 
 *  Returns  the least primitive root mod P, an odd prime; 
 *  returns NULL if factorization of P - 1 is unsuccessful . 
 */ 
{ 
	MPI *Tmp, *QQ, *R, *RR, *T; 
	unsigned int s, u, success = 1; 
	long i; 
	int r; 
 
	T = ZEROI(); 
	QQ = SUB0_I(P, 1); 
	s = FACTOR(QQ); 
	if (s == 0) 
		return (T); 
	for (i = 2; i >= 2; i++) 
	{ 
		RR = CHANGEI(i); 
		r = JACOBIB(RR, P); 
		FREEMPI(RR); 
		if (r == -1) 
		{ 
			for (u = 0; u < scount; u++) 
			{ 
				Tmp = INT0_(QQ, Q[u]); 
				R = MPOWER_(i, Tmp, P); 
				FREEMPI(Tmp); 
				if (EQONEI(R)) 
				{ 
					success = 0; 
					FREEMPI(R); 
					break; 
				} 
				FREEMPI(R); 
			}	 
			if (success) 
			{ 
				for (u = 0; u < s_count; u++) 
				{ 
					Tmp = INT0(QQ, Q_[u]); 
					R = MPOWER_(i, Tmp, P); 
					FREEMPI(Tmp); 
					if (EQONEI(R)) 
					{ 
						success = 0; 
						FREEMPI(R); 
						break; 
					} 
					FREEMPI(R); 
				}	 
			} 
			if (success) 
			{ 
				FREEMPI(QQ); 
				for (u = 0; u < s_count; u++) 
					FREEMPI(Q_[u]); 
				FREEMPI(T); 
				T = CHANGE(i); 
				break; 
			} 
			else 
				success  = 1; 
		} 
	} 
	return (T); 
} 
 
MPI *ORDERP(MPI *A, MPI *P) 
/* 
 * Returns the order of A mod P, a prime. 
 */ 
{ 
	MPI *AA, *Tmp, *QQ, *M; 
	unsigned int s, u, i; 
 
	AA = MOD(A, P); 
	Tmp = SUB0_I(AA, 1); 
	if (Tmp->S == 0)  
	{ 
		FREEMPI(Tmp); 
		FREEMPI(AA); 
		return (ONEI()); 
	} 
	FREEMPI(Tmp); 
	Tmp = ADD0_I(AA, 1); 
	if (Tmp->S == 0)  
	{ 
		FREEMPI(Tmp); 
		FREEMPI(AA); 
		return (CHANGE(2)); 
	} 
	FREEMPI(Tmp); 
	QQ = SUB0_I(P, 1); 
	/* FREE_PRIMES = 0, so we can free the Q_[i] later */  
	s = FACTOR(QQ); 
	for (u = 0; u < scount; u++) 
	{ 
		for (i = 1; i <= K[u]; i++) 
		{ 
			Tmp = INT0_(QQ, Q[u]); 
			M = MPOWER(AA, Tmp, P); 
			FREEMPI(Tmp); 
			if (!EQONEI(M)) 
			{ 
				FREEMPI(M); 
				break; 
			} 
			FREEMPI(M); 
			Tmp = QQ; 
			QQ = INT0_(QQ, Q[u]); 
			FREEMPI(Tmp); 
		} 
	} 
	for (u = 0; u < s_count; u++) 
	{ 
		for (i = 1; i <= K_[u]; i++) 
		{ 
			Tmp = INT0(QQ, Q_[u]); 
			M = MPOWER(AA, Tmp, P); 
			FREEMPI(Tmp); 
			if (!EQONEI(M)) 
			{ 
				FREEMPI(M); 
				break; 
			} 
			FREEMPI(M); 
			Tmp = QQ; 
			QQ = INT0_(QQ, Q[u]); 
			FREEMPI(Tmp); 
		} 
	} 
	FREEMPI(AA); 
	for (i = 0; i < s_count; i++) 
		FREEMPI(Q_[i]); 
	return (QQ); 
} 
 
MPI *ORDERQ(MPI *A, MPI *P, unsigned int n) 
/* 
 * Returns the order of A mod P^n, P a prime. 
 */ 
{ 
	MPI *D, *E, *Tmp, *Tmp1, *Q; 
	unsigned int h; 
 
	if (EQONEI(A)) 
		return (ONEI()); 
	if (EQMINUSONEI(A)) 
		return (CHANGE(2)); 
	if (n == 1) 
		return (ORDERP(A, P)); 
	if (P->D == 0 && P->V[0] == 2) 
	{ 
		if ((A->V[0] - 1) % 4 == 0) 
			D = ONEI(); 
		/*if ((A->V[0] + 1) % 4 == 0)*/ 
		else 
			D = CHANGE(2); 
	} 
	else 
		D = ORDERP(A, P); 
	Q = COPYI(P); 
	E = ZEROI(); 
	h = 0; 
	while (E->S == 0) 
	{ 
		Tmp = Q; 
		Q = MULTI(Q, P); 
		FREEMPI(Tmp); 
		Tmp = E; 
		E = MPOWER(A, D, Q);	 
		FREEMPI(Tmp); 
		Tmp = E; 
		E = SUB0_I(E, 1); 
		FREEMPI(Tmp); 
		h++; 
	} 
	FREEMPI(E); 
	FREEMPI(Q); 
	if (n <= h) 
		return (D); 
	else 
	{ 
		Tmp = POWERI(P, n - h); 
		Tmp1 = MULTI(Tmp, D); 
		FREEMPI(Tmp); 
		FREEMPI(D); 
		return (Tmp1); 
	} 
} 
 
MPI *ORDERM(MPI *A, MPI *M) 
/* 
 * Returns the order of A mod M. 
 */ 
{ 
	MPI *O, **Y, *Tmp, *Tmp1; 
	unsigned int i, s, *x; 
 
	if (EQONEI(A)) 
		return (ONEI()); 
	if (EQMINUSONEI(A)) 
	{ 
		if (M->D == 0 && M->V[0] == 2) 
			return (ONEI()); 
		else 
			return (CHANGE(2)); 
	} 
	/* FREE_PRIMES = 0, so we can free the Q_[i] later */  
	s = FACTOR(M); 
	x = (USI *)mmalloc(s * sizeof(USI)); 
	Y = (MPI **)mmalloc(s * sizeof(MPI *)); 
	for (i = 0; i < scount; i++) 
	{ 
		x[i] = K[i]; 
		Y[i] = CHANGE(Q[i]); 
	} 
	for (i = 0; i < s_count; i++)/* bugfix here - ANU,27/9/94. */  
	{ 
		x[i + scount] = K_[i]; 
		Y[i + scount] = COPYI(Q_[i]); 
		FREEMPI(Q_[i]); 
	} 
	O = ORDERQ(A, Y[0], x[0]); 
	for (i = 1; i < s; i++) 
	{ 
		Tmp = O; 
		Tmp1 = ORDERQ(A, Y[i], x[i]); 
		O = LCM(O, Tmp1); 
		FREEMPI(Tmp); 
		FREEMPI(Tmp1); 
	} 
	ffree(x, s * sizeof(USI)); 
	for (i = 0; i < s; i++) 
		FREEMPI(Y[i]); 
	ffree(Y, s * sizeof(MPI *)); 
	return (O); 
} 
 
void FERMAT_QUOTIENT(MPI *N) 
{ 
	USI i, n; 
	MPI *P, *Q, *O, *T1, *T2, *T3, *T4, *T33, *T44; 
	MPI *PP, *A, *B, *R; 
 
	n = CONVERTI(N); 
	O = ONEI(); 
	for (i = 2; i <= n; i++) 
	{ 
		printf("i = %u\n", i); 
		R = CHANGE(PRIME[i]); 
		P = CHANGE(PRIME[i]+ 1); 
		Q = CHANGE(PRIME[i]- 1); 
		T1 = POWERI(P, (USI)PRIME[i]); 
		FREEMPI(P); 
		T2 = POWERI(Q, (USI)PRIME[i]); 
		FREEMPI(Q); 
		T3 = SUB0I(T1, O); 
		T4 = ADD0I(T2, O); 
		FREEMPI(T1); 
		FREEMPI(T2); 
		PP = MULTI(R, R); 
		FREEMPI(R); 
		T33 = INT0(T3, PP); 
		T44 = INT0(T4, PP); 
		FREEMPI(T3); 
		FREEMPI(T4); 
		FREEMPI(PP); 
		A = LUCAS(T33); 
		FREEMPI(T33); 
		if (A->S) 
			printf("p = %lu gives a - prime quotient\n", PRIME[i]); 
		FREEMPI(A); 
		B = LUCAS(T44); 
		FREEMPI(T44); 
		if (B->S) 
			printf("p = %lu gives a + prime quotient\n", PRIME[i]); 
		FREEMPI(B); 
	} 
	FREEMPI(O); 
	return; 
} 
 
MPI *SQROOT1(MPI *A, MPI *P, USL n) 
{ 
/* Solving x^2=A (mod P^n), P an odd prime not dividing A. */ 
/* returns -1 if not soluble, otherwise returns x. */ 
 
	MPI *T, *K, *U, *V, *Tmp1, *Tmp2, *N; 
	USI i, t; 
 
	Tmp1 = INT_(P, 2); 
	T= MPOWER(A, Tmp1, P);  
	t = EQONEI(T); 
	FREEMPI(T); 
	FREEMPI(Tmp1); 
	if (t == 0) 
		return(MINUS_ONEI()); 
	if (n == 1) 
		return(SQRTM(A, P)); 
	else{ 
		U=SQROOT1(A, P, n - 1); 
		Tmp1 = MULTI(U, U); 
		V = SUBI(Tmp1, A); 
		FREEMPI(Tmp1); 
		for(i = 0; i < n - 1; i++){ 
			Tmp1 = V; 
			V = INT(V, P); 
			FREEMPI(Tmp1); 
		} 
		Tmp1 = MULT_I(U, 2); 
		Tmp2 = MINUSI(V); 
		FREEMPI(V); 
		K = CONGR(Tmp1, Tmp2, P, &N); 
		FREEMPI(Tmp1); 
		FREEMPI(Tmp2); 
		FREEMPI(N); 
		Tmp1 = POWERI(P, (USI)(n - 1)); 
		Tmp2 = MULTI(K, Tmp1); 
		FREEMPI(K); 
		FREEMPI(Tmp1); 
		Tmp1 = ADDI(U, Tmp2); 
		FREEMPI(U); 
		FREEMPI(Tmp2); 
		return(Tmp1); 
	} 
} 
 
void SQROOT1_W(Stack S) 
{ 
	USL n; 
	MPI *X; 
 
	MPI *A = stackPop(S); 
	MPI *P = stackPop(S); 
	MPI *N = stackPop(S); 
	n = CONVERTI(N); 
	X = SQROOT1(A, P, n); 
	printf("SQROOT of "); 
	PRINTI(A); 
        printf(" (mod "); 
	PRINTI(P); 
        printf("^%lu) is ", n); 
	PRINTI(X); 
	FREEMPI(X); 
	FREEMPI(A); 
	FREEMPI(P); 
	FREEMPI(N); 
	printf("\n"); 
	return; 
} 
 
USI sqroot2_number; /* global variable, used in SQROOT */ 
 
MPI *SQROOT2(MPI *A, USL n) 
{ 
/* Solving x^2=A (mod 2^n), A odd. 
 * returns -1 if not soluble, otherwise returns x. 
 * In the case of solubility, changes global variable sqroot2_number to 1,2,4  
 * according as n= 1, 2  or > 2. 
 */ 
 
	MPI *U, *V, *Tmp1, *Tmp2; 
	USI i, t; 
	USL s; 
 
	if(n == 1){ 
		sqroot2_number = 1; 
		return(ONEI()); 
	} 
	if(n == 2){ 
		s = MOD_(A, 4); 
		if (s != 1) 
			return(MINUS_ONEI()); 
		else{ 
			sqroot2_number = 2; 
			return(ONEI()); 
		} 
	} 
	s = MOD_(A, 8); 
	if(s != 1) 
		return(MINUS_ONEI()); 
	if(n == 3){ 
		sqroot2_number = 4; 
		return(ONEI()); 
	} 
	else{ 
		U = SQROOT2(A, n - 1); 
		Tmp1 = MULTI(U, U); 
                V = SUBI(Tmp1, A); 
                FREEMPI(Tmp1); 
		for(i = 0;i < n - 1;i++){ 
			Tmp1 = V; 
			V = INT_(V, 2); 
			FREEMPI(Tmp1); 
		} 
		Tmp2 = ONEI(); 
		Tmp1 = ADDI(V, Tmp2); 
		FREEMPI(Tmp2); 
		FREEMPI(V); 
		t = (Tmp1->V[0]) % 2; 
		FREEMPI(Tmp1); 
		if (t == 0){ 
			Tmp1 = POWER_I(2, (USI)(n - 2)); 
			Tmp2 = U; 
			U = ADDI(U, Tmp1); 
			FREEMPI(Tmp1); 
			FREEMPI(Tmp2); 
		} 
		return(U); 
	} 
 
} 
 
void SQROOT2_W(Stack S) 
{ 
	USL n; 
	MPI *X; 
 
	MPI *A = stackPop(S); 
	MPI *N = stackPop(S); 
	n = CONVERTI(N); 
	X = SQROOT2(A, n); 
	printf("SQROOT of "); 
	PRINTI(A); 
        printf(" (mod 2"); 
        printf("^%lu) is ", n); 
	PRINTI(X); 
	FREEMPI(X); 
	FREEMPI(A); 
	FREEMPI(N); 
	printf("\n"); 
	return; 
} 
 
MPI *SQROOT3(MPI *A, MPI *P, USL n, MPI**EXPONENT) 
/* Solving x^2=A (mod P^n), P a prime possibly dividing A. 
 * Returns -1 if not soluble, otherwise returns x. 
 * Also returns a "reduced moduli" explained as follows: 
 * If P does not divide A, the story is well-known. 
 * If P divides A, there are two cases: 
 * (i) P^n divides A, 
 * (ii) P^n does not divide A. 
 * In case (i) there are two cases: 
 * (a) n=2m+1, (b) n=2m. 
 * In case (a), the solution is x=0 (mod P^(m+1)). 
 * In case (b), the solution is x=0 (mod P^m). 
 * (These are called reduced moduli.) 
 * In case (i) gcd(A,P^n)=P^r, r2. 
 */ 
{ 
	MPI *D, *U, *V, *AA, *Tmp1, *T; 
	USI r, m, s; 
	int t; 
 
/* The next two lines are important. eg. a call sqroot(431,10,&a[],&m,&l) 
   sets global variable sqroot2_number=1, whereas a subsequent call to  
   sqroot(46,210,&a[],&m,&l) didn't call SQROOT2() and before the next fix 
   was added, sqroot2_number remained equal to 1, causing problems as 
   action is taken in SQROOT() if S[0] = 2 only if sqroot2_number > 0. */ 
	if ((P->D == 0) && P->V[0] == 2) 
		sqroot2_number = 0; 
	*EXPONENT = NULL; 
	D = MOD(A, P); 
	t = D->S; 
	FREEMPI(D); 
	if(t){ 
		*EXPONENT = POWERI(P, n); 
		if ((P->D == 0) && P->V[0] == 2) 
			return(SQROOT2(A, n)); 
		else 
			return(SQROOT1(A, P, n)); 
	} 
	else{ 
		U = POWERI(P, n); 
		V = MOD(A, U); 
		t = V->S; 
		FREEMPI(U); 
		FREEMPI(V); 
		if(t == 0){ 
			if( (n % 2) == 0) 
				*EXPONENT = POWERI(P, n/2); 
			else 
				*EXPONENT = POWERI(P, 1 + n/2); 
			return(ZEROI()); 
		} 
		r = 0; 
		AA = COPYI(A); 
		V = MOD(AA, P); 
		while((V->S == 0) && (r <= n)){ 
			Tmp1 = AA; 
			AA = INT(AA, P); 
			FREEMPI(Tmp1); 
			Tmp1 = V; 
			V = MOD(AA, P); 
			FREEMPI(Tmp1); 
			r++; 
		} 
		FREEMPI(V); 
		if(r % 2){ 
			FREEMPI(AA); 
			return(MINUS_ONEI()); 
		} 
		else{ 
			m = r / 2; 
			s = n - r; 
			*EXPONENT = POWERI(P, n - m); 
			if((P->D == 0) && (P->V[0] == 2)){ 
				T = SQROOT2(AA, s); 
				if(EQMINUSONEI(T)){ 
					FREEMPI(AA); 
					return(T); 
				} 
				else{ 
					FREEMPI(T); 
					U = POWERI(P, m); 
					T = SQROOT2(AA, s); 
					V = MULTI(U, T); 
					FREEMPI(AA); 
					FREEMPI(T); 
					FREEMPI(U); 
					return(V); 
				} 
			} 
			else{ 
				T = SQROOT1(AA, P, s); 
                                if(EQMINUSONEI(T)){ 
                                        FREEMPI(AA); 
                                        return(T); 
                                } 
                                else{ 
                                        FREEMPI(T); 
                                        U = POWERI(P, m); 
                                        T = SQROOT1(AA, P, s); 
                                        V = MULTI(U, T); 
                                        FREEMPI(AA); 
                                        FREEMPI(T); 
                                        FREEMPI(U); 
                                        return(V); 
                                } 
 
			} 
		} 
	} 
} 
 
void SQROOT3_W(Stack S) 
{ 
	USL n; 
	MPI *X, *EXPONENT; 
 
	MPI *A = stackPop(S); 
	MPI *P = stackPop(S); 
	MPI *N = stackPop(S); 
	n = CONVERTI(N); 
	X = SQROOT3(A, P, n, &EXPONENT); 
	printf("SQROOT of "); 
	PRINTI(A); 
        printf(" (mod "); 
	PRINTI(P); 
        printf("^%lu) is ", n); 
	PRINTI(X); 
	FREEMPI(X); 
        printf(" (mod "); 
	PRINTI(EXPONENT); 
	FREEMPI(A); 
	FREEMPI(P); 
	FREEMPI(N); 
	FREEMPI(EXPONENT); 
	printf(")\n"); 
	return; 
} 
 
MPI *SQROOT(MPI *A, MPI *N, MPIA *SOL, MPI **MODULUS, USI *lptr) 
/* Returns an array SOL consisting of the solutions of x^2=A (mod N),  
 * with 0<=x<=N/2 where N = prod QQ[i]^KK[i]. 
 * Returns the number of solutions (mod N) and their MODULUS if soluble, 
 * otherwise returns -1. 
 * The algorithm uses the Chinese remainder theorem after solving mod 
 * QQ[i]^KK[i], i=1,...,e=omega(N). Note N is even if and only if QQ[0]=2. 
 * Finally we join all solutions together using the CRT. 
 * Some care is needed to exhibit all solutions. We operate on the D[] 
 * array below, as follows: 
 * l= number of primes QQ[i] dividing N, for which P^a=QQ[i]^KK[i] does not  
 * divide N, while jj is the remaining number. 
 * D[] is the array formed by a single solution each of x^2=A mod P^a 
 * SS is the product of the reduced moduli for these l primes. 
 * OM is the product of the reduced moduli for the jj primes. 
 * S[] is the array formed by the moduli P^a. 
 * If l>1, we produce all 2^l l-tuples (e[0]*D[0],...,e[l-1]*D[l-1]), 
 * where e[i]=1 or -1, if s is odd or D[0]=2 and "sqroot2_number">1, but only  
 * 2^(l-1) * (l-1)-tuples (e[0]*D[0],...,e[l-2]*D[l-2]), if SS is even and  
 * "sqroot2_number"=1. 
 * It is convenient to use the CRT with D[l]=om, S[l]=0, even when OM=1, 
 * so as to produce all solutions. 
 * If SS is even, we place D[0] at the end of the D[] array, making it D[l-1]. 
 * This is done so as to conveniently operate on the initial part of the D[] 
 * array, where the initial S[i] are only odd prime powers. 
 * The program aborts if the number of prime factors of N which do not divide A 
 * is > 31. (Not an easy program to get right. Finished 12th April 2000.) 
 */ 
{ 
	USI l, e, jj, i, r, j, k, t, *KK, rr, ii;  
	MPI *C, *OM, **D, **D1, **DD, **DD1, **S, *E, *X, *AA, *B, *Y, *SS; 
	MPI *Tmp1, *Tmp2, *Tmp3, *SO, *Z, **QQ, *F, *X1; 
	int tt; 
 
	if(EQONEI(N)){ 
			*SOL = BUILDMPIA();  
			Y = ZEROI(); 
			ADD_TO_MPIA(*SOL, Y, 0); 
			FREEMPI(Y); 
			*MODULUS = ONEI(); 
			*lptr = 1; 
			return(ONEI()); 
	} 
	e = FACTOR(N); 
 
	QQ = (MPI **)mmalloc(e * sizeof(MPI *)); 
	KK = (USI *)mmalloc(e * sizeof(USI)); 
	for(i = 0; i< scount; i++){ 
		QQ[i] = CHANGE(Q[i]); 
		KK[i] = K[i]; 
	} 
	for(i = 0; i< s_count; i++){ 
		QQ[i + scount] = Q_[i]; 
		KK[i + scount] = K_[i]; 
	} 
	l = 0; 
	jj = 0; 
	OM = ONEI(); 
	SS = ONEI(); 
	D = (MPI **)mmalloc(e * sizeof(MPI *)); 
	S = (MPI **)mmalloc((e+1) * sizeof(MPI *)); 
	for(i = 0;i < e;i++){ 
		C = SQROOT3(A, QQ[i], KK[i], &E); 
		t = EQMINUSONEI(C); 
		tt = C->S; 
		if(t){ 
			FREEMPI(OM); 
			FREEMPI(E); 
			FREEMPI(SS); 
			FREEMPI(C); 
			for (ii = 0; ii < e; ii++) 
				FREEMPI(QQ[ii]); 
			ffree((char *)D, e * sizeof(MPI *)); 
			ffree((char *)S, (e+1) * sizeof(MPI *)); 
			ffree((char *)QQ, e * sizeof(MPI *)); 
			ffree((char *)KK, e * sizeof(USI)); 
			*SOL = BUILDMPIA();  
			ADD_TO_MPIA(*SOL, NULL, 0); 
			*MODULUS = (MPI *)NULL; 
			*lptr = 0; 
			return(MINUS_ONEI()); 
		} 
		else if (tt == 0){ 
			Tmp1 = OM; 
			OM = MULTI(OM, E); 
			FREEMPI(Tmp1); 
			FREEMPI(E); /* added 10/12.00 */ 
			FREEMPI(C); 
		} 
		else{ 
			D[l] = C; 
			S[l] = E; 
			Tmp1 = SS; 
			SS = MULTI(SS, S[l]); 
			FREEMPI(Tmp1); 
			l++; 
		} 
	} 
	for (i = 0; i < e; i++) 
		FREEMPI(QQ[i]); 
	ffree((char *) QQ, e * sizeof(MPI *)); 
	ffree((char *) KK, e * sizeof(USI)); 
	if(l) 
		SO = MULTI(S[0], OM); 
	else 
		SO = NULL; 
	if(l == 0){ 
		X = INT(N, OM); 
		FREEMPI(SS); 
		ffree((char *) D, e * sizeof(MPI *)); 
		ffree((char *) S, (e+1) * sizeof(MPI *)); 
		*SOL = BUILDMPIA();  
		Y = ZEROI(); 
		ADD_TO_MPIA(*SOL, Y, 0); 
		FREEMPI(Y); 
		*MODULUS = OM; 
		*lptr = 1; 
		return(X); 
	} 
	if(l == 1){ 
		if(!EQONEI(OM)){ 
			Tmp1 = ZEROI(); 
			X = CHINESE(D[0], Tmp1, S[0], OM, &Tmp2); 
			FREEMPI(Tmp2); 
			FREEMPI(Tmp1); 
		} 
		else 
			X = COPYI(D[0]); 
		if((S[0]->V[0]) % 2){ 
			Tmp1 = MULT_I(N, 2); 
			Y = INT(Tmp1, SO); 
			FREEMPI(Tmp1); 
			FREEMPI(SS); 
			FREEMPI(OM); 
			FREEMPI(D[0]); 
			ffree((char *) D, e * sizeof(MPI *)); 
			for(i=0;i 31) 
		execerror("l in SQROOT >31", ""); 
	F = POWER_I(2, l); 
	k = (USI)CONVERTI(F); 
	D1 = (MPI **)mmalloc((l + 1)* sizeof(MPI *)); 
	S[l] = OM; 
	D1[l] = ZEROI(); 
	FREEMPI(SO); 
	SO = MULTI(SS, OM); 
	FREEMPI(SS); 
	rr = 0; 
	*SOL = BUILDMPIA();  
	if((N->V[0]) % 2){ 
		for(i = 0;i < k;i++){ 
			j = i; 
			for(r = 0;r < l;r++){ 
				t = j % 2; 
				if (t) 
					D1[r] = MINUSI(D[r]); 
				else 
					D1[r] = COPYI(D[r]); 
				j = j / 2; 
			} 
			X = CHINESE_ARRAY(D1, S, &Tmp2, l + 1); 
			for(r = 0;r < l;r++) 
				FREEMPI(D1[r]); 
			Tmp1 = MULT_I(X, 2); 
			if(RSV(Tmp1, Tmp2) <= 0){ 
				ADD_TO_MPIA(*SOL, X, rr); 
				rr++; 
			} 
			FREEMPI(X); 
			FREEMPI(Tmp1); 
			FREEMPI(Tmp2); 
		} 
		for(i = 0;i < l;i++){ 
			FREEMPI(D[i]); 
			FREEMPI(S[i]); 
		} 
		FREEMPI(D1[l]); 
		FREEMPI(S[l]); 
		ffree((char *) D, e * sizeof(MPI *)); 
		ffree((char *) S, (e+1) * sizeof(MPI *)); 
		ffree((char *) D1, (l + 1) * sizeof(MPI *)); 
		Tmp1 = MULTI(F, N); 
		FREEMPI(F); 
		Z = INT0(Tmp1, SO); 
		FREEMPI(Tmp1); 
		*MODULUS = SO; 
		*lptr = rr; 
		return(Z); 
	} 
	else{/* N is even */ 
		DD = (MPI **)mmalloc((l + 1) * sizeof(MPI *)); 
		DD1 = (MPI **)mmalloc((l + 1) * sizeof(MPI *)); 
		if(sqroot2_number == 4) 
			DD1[l] = ZEROI(); 
		AA = D[0]; 
		B = S[0]; 
		for(r = 1;r < l;r++){ 
			D[r - 1] = D[r]; 
			S[r - 1] = S[r]; 
		} 
		D[l - 1] = AA; 
		S[l - 1] = B; 
		if(sqroot2_number == 4){ 
			for(r = 0;r < l - 1;r++) 
				DD[r] = COPYI(D[r]);	 
			Tmp2 = INT_(S[l - 1], 2); 
			Tmp3 = ADDI(D[l - 1], Tmp2); 
			FREEMPI(Tmp2); 
			DD[l - 1] = MOD(Tmp3, S[l - 1]); 
			FREEMPI(Tmp3); 
		} 
		if(sqroot2_number == 1) 
			k = k / 2; 
			 
		for(i = 0;i < k;i++){ 
			j = i; 
			for(r = 0;r < l;r++){ 
				t = j % 2; 
				if (t){ 
					D1[r] = MINUSI(D[r]); 
					if(sqroot2_number == 4) 
						DD1[r] = MINUSI(DD[r]); 
				} 
				else{ 
					D1[r] = COPYI(D[r]); 
					if(sqroot2_number == 4) 
						DD1[r] = COPYI(DD[r]); 
				} 
				j = j / 2; 
			} 
			X = CHINESE_ARRAY(D1, S, &Tmp2, l + 1); 
			Tmp1 = MULT_I(X, 2); 
			if(RSV(Tmp1, Tmp2) <= 0){ 
				ADD_TO_MPIA(*SOL, X, rr); 
				rr++; 
			} 
			FREEMPI(Tmp1); 
			FREEMPI(X); 
			FREEMPI(Tmp2); 
			if(sqroot2_number == 4){ 
				X = CHINESE_ARRAY(DD1, S, &Tmp2, l + 1); 
				Tmp1 = MULT_I(X, 2); 
				if(RSV(Tmp1, Tmp2) <= 0){ 
					ADD_TO_MPIA(*SOL, X, rr); 
					rr++; 
				} 
				FREEMPI(X); 
				FREEMPI(Tmp1); 
				FREEMPI(Tmp2); 
			} 
			for(r = 0;r < l;r++){ 
				FREEMPI(D1[r]); 
				if(sqroot2_number == 4) 
					FREEMPI(DD1[r]); 
			} 
		} 
		for(i = 0;i < l;i++){ 
			FREEMPI(D[i]); 
			FREEMPI(S[i]); 
		} 
		FREEMPI(D1[l]); 
		if(sqroot2_number == 4){ 
			FREEMPI(DD1[l]); 
			for(i = 0;i < l;i++) 
				FREEMPI(DD[i]); 
		} 
		FREEMPI(S[l]); 
		ffree((char *) D, e * sizeof(MPI *)); 
		ffree((char *) S, (e+1) * sizeof(MPI *)); 
		ffree((char *) D1, (l + 1) * sizeof(MPI *)); 
		ffree((char *) DD1, (l + 1) * sizeof(MPI *)); 
		ffree((char *) DD, (l + 1) * sizeof(MPI *)); 
		Tmp1 = MULTI(F, N); 
		if(sqroot2_number == 1){ 
			Tmp2 = Tmp1; 
			Tmp1 = INT0_(Tmp1, 2); 
			FREEMPI(Tmp2); 
		} 
		if(sqroot2_number == 4){ 
			Tmp2 = Tmp1; 
			Tmp1 = MULT_I(Tmp1, 2); 
			FREEMPI(Tmp2); 
		} 
		FREEMPI(F); 
		Z = INT0(Tmp1, SO); 
		FREEMPI(Tmp1); 
		*MODULUS = SO; 
		*lptr = rr; 
		return(Z); 
	} 
} 
 
MPI *SQROOTX(MPI *A, MPI *N, MPIA *Y, MPI **M, USI *l) 
{ 
	MPI *tmp; 
 
	if(N->S <= 0){ 
		printf("N <= 0\n"); 
		return(NULL); 
	} 
	else 
	{ 
		tmp = SQROOT(A, N, Y, M, l); 
		return(tmp); 
	} 
} 
 
void CORNACCHIA(MPI *A, MPI *B, MPI *M) 
/* Cornacchia's algorithm. See L'algorithme de Cornacchia, A. Nitaj, 
 * Expositiones Mathematicae, 358-365. 
 */ 
{ 
	MPI *A1, *A2, *Tmp1, *TT, *T1, *T2, *N; 
	MPI *AA, *BB, *R, *Q1, *QQ, *MA, *MB;  
	MPIA ARRAY; 
	USI ll, i, jj; 
	int t1, t2; 
 
	A1 = INVERSEM(A, M);	 
	Tmp1 = MINUSI(B); 
	A2 = MULTI(A1, Tmp1); 
	FREEMPI(A1); 
	FREEMPI(Tmp1); 
	MA = INT0(M, A); 
	MB = INT0(M, B); 
	N = SQROOTX(A2, M, &ARRAY, &Tmp1, &ll); 
	FREEMPI(N); 
	FREEMPI(A2); 
	FREEMPI(Tmp1); 
	for( i = 0; i < ll; i++){ 
		TT = ZEROI(); 
		T1 = ONEI(); 
		AA = COPYI(M); 
		BB = COPYI(ARRAY->A[i]); 
		t2 = 0; 
		jj = 0; 
		R = COPYI(AA); 
		T2 = ZEROI(); 
		while(t2 <= 0){ 
			Tmp1 = MULTI(R, R); 
			t1 = RSV(Tmp1, MA); 
			FREEMPI(Tmp1); 
			if(t1 <= 0){ 
				printf("X="); 
				PRINTI(R); 
				printf(", Y="); 
				if(T2->S == -1) 
					T2->S = 1; 
				PRINTI(T2); 
				printf("\n"); 
				break; 
			} 
			jj++; 
			if(jj == 1){ 
				FREEMPI(R); 
				R = COPYI(BB); 
				FREEMPI(T2); 
				T2 = ONEI(); 
				t2 = RSV(T2, MB); 
			} 
			if(jj > 1){ 
				if(jj==2){ 
					FREEMPI(R); 
					FREEMPI(T2); 
				} 
				R = MOD0(AA, BB); 
				Q1 = INT0(AA, BB); 
				FREEMPI(AA); 
				AA = BB; 
				BB = R; 
				QQ = MINUSI(Q1); 
				FREEMPI(Q1); 
				T2 = MULTABC(TT, QQ, T1); 
				FREEMPI(TT); 
				FREEMPI(QQ); 
				Tmp1= MULTI(T2, T2); 
				t2 = RSV(Tmp1, MB); 
				FREEMPI(Tmp1); 
				TT = T1; 
				T1 = T2; 
			} 
		} 
		FREEMPI(TT); 
		FREEMPI(T1); 
		if(jj == 1){ 
			FREEMPI(T2); 
			FREEMPI(R); 
		} 
		FREEMPI(AA); 
		FREEMPI(BB); 
	} 
	FREEMPIA(ARRAY); 
	FREEMPI(MA); 
	FREEMPI(MB); 
} 
 
 
MPI *CORNACCHIAX(MPI *A, MPI *B, MPI *M) 
{ 
	MPI *Tmp; 
	int t; 
	USI s; 
 
	if (A->S <= 0) 
	{ 
	  printf("A <= 0\n"); 
	  return NULL; 
	} 
	if (B->S <= 0) 
	{ 
	  printf("B <= 0\n"); 
	  return NULL; 
	} 
	Tmp = ADD0I(A, B); 
	t = RSV(Tmp, M); 
	FREEMPI(Tmp); 
	if (t > 0) 
	{ 
	  printf("M < A + B\n"); 
	  return NULL; 
	} 
	Tmp = GCD(A, B); 
	s = EQONEI(Tmp); 
	FREEMPI(Tmp); 
	if (s == 0) 
	{ 
	  printf("gcd(A,B) > 1\n"); 
	  return NULL; 
	} 
	Tmp = GCD(A, M); 
	s = EQONEI(Tmp); 
	FREEMPI(Tmp); 
	if (s == 0) 
	{ 
	  printf("gcd(A,M) > 1\n"); 
	  return NULL; 
	} 
	 
	CORNACCHIA(A, B, M); 
	return(ONEI()); 
} 
 
void GAUSS(MPI *A, MPI *B, MPI *C, MPI *N, MPI **alpha, MPI **gamma, MPI **M) 
/* input: gcd(A,B,C)=1, |N|>1.  
 * output: (alpha,gamma), where A*alpha^2+B*alpha*gamma+C*gamma^2=M, gcd(M,N)=1. 
 */ 
{ 
	MPI *ABSN, **QQ, *TMP1, *TMP2, *TMP3, *TMP4;  
	MPI **XX, **YY, *MM, *NN, *G; 
	USI e, i; 
	int s, t; 
 
	ABSN = ABSI(N); 
	e = FACTOR(ABSN); 
	FREEMPI(ABSN); 
	QQ = (MPI **)mmalloc(e * sizeof(MPI *)); 
	for(i = 0; i< scount; i++) 
                QQ[i] = CHANGE(Q[i]); 
	for(i = 0; i< s_count; i++) 
                QQ[i + scount] = Q_[i]; 
	XX = (MPI **)mmalloc(e * sizeof(MPI *)); 
	YY = (MPI **)mmalloc(e * sizeof(MPI *)); 
	for(i = 0; i < e; i++){ 
		TMP1 = MOD(A, QQ[i]); 
		TMP2 = MOD(C, QQ[i]); 
		s = TMP1->S; 
		t = TMP2->S; 
		FREEMPI(TMP1); 
		FREEMPI(TMP2); 
		if(s){ 
			XX[i] = ONEI(); 
			YY[i] = ZEROI(); 
		} 
		if(!s && t){ 
			XX[i] = ZEROI(); 
			YY[i] = ONEI(); 
		} 
		if(!s && !t){ 
			XX[i] = ONEI(); 
			YY[i] = ONEI(); 
		} 
	} 
	TMP1 = CHINESE_ARRAY(XX, QQ, &MM, e); 
	TMP2 = CHINESE_ARRAY(YY, QQ, &NN, e); 
	FREEMPI(MM); 
	FREEMPI(NN); 
	G = GCD(TMP1, TMP2); 
	*alpha = INT(TMP1, G); 
	FREEMPI(TMP1); 
	*gamma = INT(TMP2, G); 
	FREEMPI(TMP2); 
	FREEMPI(G); 
	TMP1 = MULTI3(A, *alpha, *alpha); 
	TMP2 = MULTI3(B, *alpha, *gamma); 
	TMP3 = MULTI3(C, *gamma, *gamma); 
	TMP4 = ADDI(TMP1, TMP2); 
	*M = ADDI(TMP4, TMP3); 
	FREEMPI(TMP1); 
	FREEMPI(TMP2); 
	FREEMPI(TMP3); 
	FREEMPI(TMP4); 
	for (i = 0; i < e; i++){ 
		FREEMPI(QQ[i]); 
		FREEMPI(XX[i]); 
		FREEMPI(YY[i]); 
	} 
	ffree((char *)QQ, e * sizeof(MPI *)); 
	ffree((char *)XX, e * sizeof(MPI *)); 
	ffree((char *)YY, e * sizeof(MPI *)); 
	return; 
} 
 
/* 
#include  
#include "unistd.h" 
*/ 
 
MPI *PRIME_GENERATOR(MPI *M, MPI *N) 
/* lists the primes P satisfying M <= P <= N.   
 * Returns the number of such primes. 
 */ 
{ 
	unsigned long j, k; 
	MPI *C, *P, *Temp, *Temp1, *Temp2, *MM, *MMM, *NN, *ONE; 
	unsigned int c=0; 
	int t; 
	char buff[20]; 
        FILE *outfile; 
 
	ONE = ONEI(); 
	strcpy(buff, "primes.out"); 
	if(access(buff, R_OK) == 0) 
		  unlink(buff); 
	outfile = fopen(buff, "w"); 
 
	if(RSV(M, N)==1){ 
		Temp = COPYI(N); 
		NN=COPYI(M); 
		MM=Temp; 
	} 
	else{ 
		MM=COPYI(M); 
		NN=COPYI(N); 
	} 
	if(MM->D==0 && MM->V[0]==2){ 
		c++; 
		printf("2\n"); 
		fprintf(outfile, "2\n"); 
	} 
	t = (MM->V[0])% 2; 
	MMM = COPYI(MM); 
	if(t == 0){ 
		Temp = MM; 
		MM = ADD0I(MM, ONE); 
		FREEMPI(Temp); 
	} 
	FREEMPI(ONE); 
	P = COPYI(MM); 
	while (RSV(P, NN) <= 0){ 
		j = 1; 
		k = 1; 
		while(1){ 
			Temp2 = CHANGE(PRIMES[k]); 
			Temp1 = MULT_I(Temp2, (long)PRIMES[k]); 
			FREEMPI(Temp2); 
			t = RSV(P, Temp1); 
			FREEMPI(Temp1); 
			if(t < 0){ 
				break; 
			} 
			if(MOD0_(P, PRIMES[k])==0){ 
				j=0; 
				break; 
			} 
			if(k >= 9591) 
				break; 
			k++; 
           	} 
		if(j == 1){ 
			c++; 
			PRINTI(P); printf("\n"); 
			FPRINTI(outfile, P); fprintf(outfile, "\n"); 
		} 
		Temp = P; 
		P = ADD0_I(P, (USL)2); 
		FREEMPI(Temp); 
	} 
	FREEMPI(P); 
	printf("the number of primes in the range "); 
	PRINTI(MMM);  
	printf(" to "); 
	PRINTI(NN);  
	fprintf(outfile, "the number of primes in the range "); 
	FPRINTI(outfile, MMM);  
	fprintf(outfile, " to "); 
	FPRINTI(outfile, NN);  
	printf(" is %u\n",c); 
	fprintf(outfile," is %u\n",c); 
	fclose(outfile); 
	C = CHANGE(c); 
	FREEMPI(MM); 
	FREEMPI(NN); 
	FREEMPI(MMM); 
	return (C); 
} 
 
MPI *PRIME_GENERATORX(MPI *M, MPI *N) 
{ 
	MPI *BOUND, *ONE, *NUMBER; 
	int s, t; 
 
	BOUND = BUILDMPI(3); 
	BOUND->V[0]  = 58368; 
	BOUND->V[1]  = 21515; 
	BOUND->V[2]  = 2; 
	BOUND->S=1; 
	if(RSV(N, BOUND) >= 0){ 
		printf("n>="); PRINTI(BOUND); printf("\n"); 
		FREEMPI(BOUND); 
		return (NULL); 
	} 
	FREEMPI(BOUND); 
	ONE = ONEI(); 
	s = RSV(M, ONE); 
	t = RSV(N, ONE); 
	FREEMPI(ONE); 
	if(s <= 0){ 
		printf("m <= 1\n"); 
		return (NULL); 
	} 
	if(t <= 0){ 
		printf("n <= 1\n"); 
		return (NULL); 
	} 
	NUMBER = PRIME_GENERATOR(M, N); 
	return (NUMBER); 
} 
 
MPI *SIGMAK(USI k, MPI *N) 
/* 
 *  Returns the sum of the kth powers of the divisors of N, 
 *  returns NULL if factorization unsuccessful . 
 *  Here 0 < k <= 10000 and N >= 1. 
 */ 
{ 
	MPI *U, *V, *W, *Tmp; 
	unsigned int i, s; 
 
	if (EQONEI(N)) 
		return (ONEI()); 
	/* FREE_PRIMES = 0, so we can free the Q_[i] later */  
	s = FACTOR(N); 
	if (s == 0) 
	{ 
		return ((MPI *)NULL); 
	} 
	U = ONEI(); 
	for (i = 0; i < scount; i++) 
	{ 
		V = POWER_I((long)(Q[i]), k*(K[i] + 1)); 
		Tmp = V; 
		V = SUB0_I(V, 1); 
		FREEMPI(Tmp); 
		W = POWER_I((long)(Q[i]), k); 
		Tmp = W; 
		W = SUB0_I(W, 1); 
		FREEMPI(Tmp); 
		Tmp = V; 
		V = INT0(V, W); 
		FREEMPI(Tmp); 
		FREEMPI(W); 
		Tmp = U; 
		U = MULTI(U, V); 
		FREEMPI(Tmp); 
		FREEMPI(V); 
	} 
	for (i = 0; i < s_count; i++) 
	{	V = POWERI(Q_[i], k*(K_[i] + 1)); 
		Tmp = V; 
		V = SUB0_I(V, 1); 
		FREEMPI(Tmp); 
		W = POWERI(Q_[i], k); 
		Tmp = W; 
		W = SUB0_I(W, 1); 
		FREEMPI(Tmp); 
		Tmp = V; 
		V = INT0(V, W); 
		FREEMPI(W); 
		FREEMPI(Tmp); 
		Tmp = U; 
		U = MULTI(U, V); 
		FREEMPI(Tmp); 
		FREEMPI(V); 
	} 
	for (i = 0; i < s_count; i++) 
		FREEMPI(Q_[i]); 
	return (U); 
} 
 
/* 
 *  Returns the sum of the kth powers of the divisors of N, 
 *  returns NULL if factorization unsuccessful . 
 *  Here 0 < k <= 10000 and N >= 1. 
 */ 
MPI *SIGMAKX(MPI *K, MPI *N){ 
	USI k; 
	 
	if (K->S <= 0){ 
	    printf("k <= 0\n");	 
	    return(NULL); 
	} 
	if (N->S <= 0){ 
	    printf("n <= 0\n");	 
	    return(NULL); 
	} 
	if (K->D > 0){ 
	    printf("k >= 2^16\n");	 
	    return(NULL); 
	} 
	k = (USI)CONVERTI(K); 
	if(k > 10000){ 
	    printf("k > 10000\n");	 
	    return(NULL); 
	} 
	return(SIGMAK(k, N)); 
} 
 
 
/* TAU(n) is Ramanujan's tau function. See T.M. Apostol, 'Modular functions 
 * and Dirichlet series in number theory', 20-22, 140. 
 * We assume n < 2^16 
 */ 
MPI *TAU(USI n){ 
	USI i; 
	MPI *S, *T, *TT, *TEMP1, *TEMP2, *TEMP3, *TEMP, *TEMPS; 
 
	if(n == 1){ 
		return(ONEI()); 
	} 
	S = ZEROI(); 
	for(i=1;iS <= 0){ 
	    printf("n <= 0\n");	 
	    return(NULL); 
	} 
	if (N->D > 0){ 
	    printf("n >= 2^16\n");	 
	    return(NULL); 
	} 
	n = (USI)CONVERTI(N); 
	return(TAU(n)); 
} 
 
MPI *TAU_PRIMEPOWER(USI n, USI p){ 
	USI j, t, temp1, temp2; 
	MPI *S, *T, *U, *TEMP, *TEMP1, *TEMP2; 
 
	t = n/2; 
	S = ZEROI(); 
	for(j = 0; j <= t;j++){ 
		temp1 = n - j; 
		temp2 = temp1 - j; 
		TEMP = BINOMIAL(temp1, temp2); 
		TEMP1 = POWER_I(p, 11 * j); 
		T = TAU(p);	 
		TEMP2 = POWERI(T, temp2); 
		FREEMPI(T); 
		U = MULTI3(TEMP, TEMP1, TEMP2); 
		FREEMPI(TEMP); 
		FREEMPI(TEMP1); 
		FREEMPI(TEMP2); 
		if(j % 2){ 
			U->S = -(U->S); 
		} 
		TEMP = S; 
		S = ADDI(S, U); 
		FREEMPI(TEMP); 
		FREEMPI(U); 
	}	 
	return(S); 
} 
 
MPI *TAU_PRIMEPOWERX(MPI *N, MPI *P){ 
	USI n, p, t; 
	MPI *T; 
	if (N->S <= 0){ 
	    printf("n <= 0\n");	 
	    return(NULL); 
	} 
	if (N->D > 0){ 
	    printf("n >= 2^16\n");	 
	    return(NULL); 
	} 
	n = (USI)CONVERTI(N); 
	T = LUCAS(P); 
	t = EQONEI(T); 
	FREEMPI(T); 
	if (t== 0){ 
	    printf("p is not prime\n");	 
	    return(NULL); 
	} 
 
	p = (USI)CONVERTI(P); 
	return(TAU_PRIMEPOWER(n, p)); 
} 
 
MPI *TAU_COMPOSITE(USI n){ 
	USI i, d, *KGLOB, *QGLOB; 
	MPI *U, *N, *TEMP, *T; 
 
	U = ONEI(); 
	N = CHANGE(n); 
	d = FACTOR(N); 
	FREEMPI(N); 
	KGLOB = (USI *)mmalloc(d * sizeof(USI)); 
	QGLOB = (USI *)mmalloc(d * sizeof(USI)); 
	for(i = 0; i < scount; i++){ 
		KGLOB[i] = K[i]; 
		QGLOB[i] = Q[i]; 
	} 
	for(i = scount; i < d; i++){ 
		KGLOB[i] = K_[i]; 
		QGLOB[i] = CONVERTI(Q_[i]); /* n < 2^32 here */ 
	} 
	for(i = 0; i < d; i++){ 
		TEMP = U; 
		T = TAU_PRIMEPOWER(KGLOB[i], QGLOB[i]); 
		U = MULTI(U, T); 
		FREEMPI(TEMP); 
		FREEMPI(T); 
	} 
	for (i = 0; i < s_count; i++) 
		FREEMPI(Q_[i]); 
	ffree(KGLOB, d * sizeof(USI)); 
	ffree(QGLOB, d * sizeof(USI)); 
	return(U); 
} 
 
MPI *TAU_COMPOSITEX(MPI *N){ 
	USI n; 
 
	if (N->S <= 0){ 
	    printf("n <= 0\n");	 
	    return(NULL); 
	} 
	if (N->D > 0){ 
	    printf("n >= 2^16\n");	 
	    return(NULL); 
	} 
	n = (USI)CONVERTI(N); 
	return(TAU_COMPOSITE(n)); 
}