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


/* pI.c */ 
 
#include  
#include  
#include "integer.h" 
#include "pI.h" 
#include "fun.h" 
 
 
#ifndef DEBUG 
 
POLYI BANKI = NULL; 
 
#endif 
 
#ifndef DEBUG 
void SAVEI(Ptr) 
POLYI Ptr; 
/* 
This routine takes a POLYI (which is a linked list of TERMI's) that is 
no longer needed, and links it onto the start of the free list BANKI, 
which itself is just a linked list opf TERMI's. 
*/ 
{ 
	POLYI tmp; 
 
	tmp=Ptr; 
	while(tmp->NEXT) 
	  tmp=tmp->NEXT; 
	tmp->NEXT = BANKI; 
	BANKI = Ptr; 
	Ptr = NULL; 
} 
#endif 
 
POLYI CREATEPI() 
/* 
 * If there is anything in BANKI (the memory bank of TERMI's) then use that, 
 * otherwise allocate a new one. 
 * No initialisation is performed 
*/ 
{ 
	POLYI Ptr; 
	#ifndef DEBUG 
	if (BANKI) 
	{ 
		Ptr = BANKI; 
		BANKI = BANKI->NEXT; 
	} 
	else 
	#endif 
	Ptr = (POLYI)mmalloc(sizeof(struct TERMI)); 
	return (Ptr);	 
} 
 
int DEGREEPI(POLYI Pptr) 
/* 
 * returns the degree of the polynomial Pptr. 
 */ 
{ 
	if (Pptr == NULL) 
		return (-1); 
	else 
		return (Pptr->DEG); 
} 
 
MPI *LEADPI(POLYI Pptr) 
/* 
 * *Aptr is the  leading coefficient of the polynomial Pptr. 
 */ 
{ 
	if (Pptr == NULL) 
		return ZEROI(); 
	else 
		return COPYI(Pptr->COEF); 
} 
 
void DELETEPI(POLYI Pptr) 
/* 
 * returns back to the system storage dynamically allocated to the linked list 
 * which Pptr points to. 
 */ 
{ 
	POLYI Qtmp, orig; 
	 
	if(!Pptr) return; 
	orig = Pptr; 
	while (Pptr != NULL) 
	{ 
 		Qtmp = Pptr->NEXT; 
		FREEMPI(Pptr->COEF); 
#ifdef DEBUG /* This fix was due to Peter Adams on 30/6/94 */ 
		SAVEPI(Pptr); 
#endif 
		Pptr= Qtmp; 
	} 
#ifndef DEBUG 
	SAVEPI(orig); 
#endif 
	return; 
} 
 
void PINSERTPI(int DEG, MPI *COEF, POLYI *Pptr, USI OPT) 
/* 
 * inserts a copy of a single term *Qptr into polynomial *Pptr. 
 * It has two options that control the insertion in case a term of *Pptr already 
 * has the degree of *Qptr, If OPT = 0, then the term is replaced; if OPT = 1, 
 * then the coefficient of *Qptr is added to that of the corresponding term of 
 *  *Pptr. 
 */ 
{ 
	POLYI CURSOR, Ttmp; 
	MPI *TempI; 
 
	if (*Pptr == NULL) 
	{ 
		*Pptr = CREATEPI(); 
		(*Pptr)->DEG = DEG; 
		(*Pptr)->COEF = COPYI(COEF); 
		(*Pptr)->NEXT = NULL; 
		return; 
	} 
	else 
	{ 
		CURSOR = *Pptr; 
		while ((CURSOR->DEG > DEG) && (CURSOR->NEXT != NULL)) 
			CURSOR = CURSOR->NEXT; 
		if (CURSOR->DEG < DEG) 
		{ 
			/* Qptr inserted before CURSOR */ 
			Ttmp = CREATEPI(); 
			Ttmp->DEG = CURSOR->DEG; 
			Ttmp->COEF = CURSOR->COEF; 
			Ttmp->NEXT = CURSOR->NEXT; 
			CURSOR->DEG = DEG; 
			CURSOR->COEF = COPYI(COEF); 
			CURSOR->NEXT = Ttmp; 
			return; 
		} 
		else if (CURSOR->DEG == DEG) 
		{ 
			if (OPT == 0) 
				CURSOR->COEF = COPYI(COEF); 
			else 
			{ 
				TempI = CURSOR->COEF; 
				CURSOR->COEF = ADDI(CURSOR->COEF, COEF); 
				FREEMPI(TempI); 
			} 
			return; 
		} 
		else 
		{ 
			/* CURSOR->DEG > Qptr->DEG and CURSOR->NEXT === NULL */ 
			/* Qptr inserted at end */ 
			Ttmp = CREATEPI(); 
			Ttmp->DEG = DEG; 
			Ttmp->COEF = COPYI(COEF); 
			Ttmp->NEXT = NULL; 
			CURSOR->NEXT = Ttmp; 
			return; 
		} 
	} 
} 
 
void PURGEPI(POLYI *Pptr) 
/* 
 * gets rid of any zero coefficients in the polynomial Pptr. 
 */ 
{ 
	POLYI R1tmp, R2tmp; 
 
	if (*Pptr != NULL) 
	{ 
		R1tmp = *Pptr; 
		R2tmp = (*Pptr)->NEXT; 
		while (R2tmp != NULL) 
		{ 
			/* purge non-leading terms */ 
			if ((R2tmp->COEF)->S == 0) 
			{ 
				R1tmp->NEXT = R2tmp->NEXT; 
				R2tmp->NEXT = NULL; 
				DELETEPI(R2tmp); 
				R2tmp = R1tmp->NEXT; 
			} 
			else 
			{ 
				R1tmp = R2tmp; 
				R2tmp = R2tmp->NEXT; 
			} 
		} 
		if (((*Pptr)->COEF)->S == 0) 
		{ 
			/* purge leading term */ 
			R1tmp = *Pptr; 
			*Pptr = (*Pptr)->NEXT; 
			R1tmp->NEXT = NULL; 
			DELETEPI(R1tmp); 
		} 
	} 
	return; 
} 
 
POLYI COPYPI(POLYI Pptr) 
/* 
 * makes a copy of the polynomial Pptr. 
 */ 
{ 
	POLYI Rtmp, Sptr; 
 
	Sptr = NULL; 
	Rtmp = Pptr; 
	while (Rtmp != NULL) 
	{ 
		PINSERTPI(Rtmp->DEG, Rtmp->COEF, &Sptr, 0); 
		Rtmp = Rtmp->NEXT; 
	} 
	return (Sptr); 
} 
  
void PRINTPI(POLYI Pptr) 
{ 
  FPRINTPI(stdout, Pptr); 
} 
 
void FPRINTPI(FILE *outfile, POLYI Pptr) 
/* 
 * outputs the terms of the polynomial Pptr. 
 */ 
{ 
	POLYI CURSOR; 
	int k, l; 
 
	if (Pptr == NULL) 
	{ 
		fprintf(outfile, "0"); 
		return; 
	} 
	else 
	{ 
		CURSOR = Pptr; 
		k = DEGREEPI(Pptr); 
		while (CURSOR != NULL) 
		{ 
			l = (CURSOR->COEF)->S; 
			if (l == -1) 
			{ 
				(CURSOR->COEF)->S = 1; 
				fprintf(outfile, "- "); 
			} 
			else 
			{ 
				if (CURSOR->DEG != k) 
					fprintf(outfile, "+ "); 
			} 
			if (CURSOR->DEG == 0 || !EQONEI(CURSOR->COEF)) 
				FPRINTI(outfile, CURSOR->COEF); 
			if (l == -1) 
				(CURSOR->COEF)->S = -1; 
			if (CURSOR->DEG == 1) 
				fprintf(outfile, "X"); 
			if (CURSOR->DEG > 1) 
				fprintf(outfile, "X^%d", CURSOR->DEG); 
			if (CURSOR->NEXT != NULL) 
				fprintf(outfile, " "); 
			CURSOR = CURSOR->NEXT; 
		} 
		return; 
	} 
} 
 
 
 
POLYI SCALARPI(MPI *Cptr, POLYI Pptr) 
/* 
 * multiplying the polynomial Pptr by the MPI *Cptr. 
 */ 
{ 
	POLYI Sptr, Rtmp; 
	MPI *TempI; 
 
	if (Pptr == NULL || Cptr->S == 0) 
		Sptr = NULL; 
	else 
	{ 
		Sptr = COPYPI(Pptr); 
		Rtmp = Sptr; 
		while (Rtmp != NULL) 
		{ 
			TempI = Rtmp->COEF; 
			Rtmp->COEF = MULTI(Rtmp->COEF, Cptr); 
			FREEMPI(TempI); 
			Rtmp = Rtmp->NEXT; 
		} 
	} 
	return (Sptr); 
} 
 
POLYI ADDPI(POLYI Pptr, POLYI Qptr) 
/* 
 * returns the sum of two polynomials. 
 */ 
{ 
	POLYI CURSOR, Sptr; 
 
		Sptr = COPYPI(Pptr); 
		CURSOR = Qptr; 
		while (CURSOR != NULL) 
		{ 
			PINSERTPI(CURSOR->DEG, CURSOR->COEF, &Sptr, 1); 
			CURSOR = CURSOR->NEXT; 
		} 
		PURGEPI(&Sptr); 
		return (Sptr); 
} 
 
POLYI SUBPI(POLYI Pptr, POLYI Qptr) 
/* 
 * returns the difference Pptr - Qptr of two polynomials. 
 */ 
{ 
	POLYI CURSOR, Sptr; 
	MPI *TempI; 
 
		Sptr = COPYPI(Pptr); 
		if (Qptr == NULL) 
			return (Sptr); 
		CURSOR = Qptr; 
		while (CURSOR != NULL) 
		{ 
			TempI = MINUSI(CURSOR->COEF); 
			PINSERTPI(CURSOR->DEG, TempI, &Sptr, 1); 
			FREEMPI(TempI); 
			CURSOR = CURSOR->NEXT; 
		} 
		PURGEPI(&Sptr); 
		return (Sptr); 
} 
 
POLYI MULTPI(POLYI Pptr, POLYI Qptr) 
/* 
 * returns the product of two polynomials. 
 */ 
{ 
	POLYI Sptr, CURSOR_P, CURSOR_Q; 
	MPI *TempI; 
	int k; 
 
	if (Pptr == NULL || Qptr == NULL) 
		return (NULL); 
	Sptr = NULL; 
	CURSOR_P = Pptr; 
	while (CURSOR_P != NULL) 
	{ 
		CURSOR_Q = Qptr; 
		while (CURSOR_Q != NULL) 
		{ 
			k = CURSOR_P->DEG + CURSOR_Q->DEG; 
			TempI = MULTI(CURSOR_P->COEF, CURSOR_Q->COEF); 
			PINSERTPI(k, TempI, &Sptr, 1); 
			FREEMPI(TempI); 
			CURSOR_Q = CURSOR_Q->NEXT; 
		} 
		CURSOR_P = CURSOR_P->NEXT; 
	} 
	PURGEPI(&Sptr); 
	return (Sptr); 
} 
 
MPI *VALPI(POLYI Pptr, MPI *Cptr) 
/* 
 * Evaluating the polynomial Pptr at the MPI *Cptr. 
 */ 
{ 
	int k; 
	MPI *B, *Aptr, *TempI; 
	POLYI CURSOR; 
 
	if (Pptr == NULL) 
		return ZEROI(); 
	else 
		Aptr = COPYI(Pptr->COEF); 
	CURSOR = Pptr; 
	while (CURSOR != NULL) 
	{ 
		if (CURSOR->NEXT == NULL) 
			k = DEGREEPI(CURSOR); 
		else 
			k = DEGREEPI(CURSOR) - DEGREEPI(CURSOR->NEXT); 
		B = POWERI(Cptr, (unsigned int)k); 
		TempI = Aptr; 
		Aptr = MULTI(Aptr, B); 
		FREEMPI(B); 
		FREEMPI(TempI); 
		CURSOR = CURSOR->NEXT; 
		if (CURSOR != NULL) 
		{ 
			TempI = Aptr; 
			Aptr = ADDI(Aptr, CURSOR->COEF); 
			FREEMPI(TempI); 
		} 
	} 
	return (Aptr); 
} 
 
POLYI DIVPI(POLYI Fptr, POLYI Gptr) 
/* 
 * Pseudo-division of polynomials: see Knuth, Vol 2, p.407  
 * and H. Flanders, Scientific Pascal, p.510. 
 */ 
{ 
	POLYI F, Tmp, Htmp, CURSOR, Qptr; 
	int j, d; 
	MPI *A, *G, *TempI; 
 
	Qptr = NULL; 
	d = DEGREEPI(Gptr); 
	j = DEGREEPI(Fptr) - d; 
	if (j < 0) 
		return (Qptr); 
	else 
	{ 
		F = COPYPI(Fptr); 
		G = LEADPI(Gptr); 
		A = POWERI(G, (unsigned int)(j + 1)); 
		Tmp = F; 
		F = SCALARPI(A, Tmp); 
		FREEMPI(A); 
		DELETEPI(Tmp); 
		while ((j = DEGREEPI(F)) >= d) 
		{ 
			j = j - d; 
			A = LEADPI(F); 
			TempI = A; 
			A = INTI(A, G); 
			FREEMPI(TempI); 
			Htmp = COPYPI(Gptr); 
			CURSOR = Htmp; 
			do 
			{ 
				CURSOR->DEG = j + CURSOR->DEG; 
				TempI = CURSOR->COEF; 
				CURSOR->COEF = MINUSI(CURSOR->COEF); 
				FREEMPI(TempI); 
				TempI = CURSOR->COEF; 
				CURSOR->COEF = MULTI(CURSOR->COEF, A); 
				FREEMPI(TempI); 
				CURSOR = CURSOR->NEXT; 
			} 
			while (CURSOR != NULL); 
			Tmp = F; 
			F = ADDPI(Tmp, Htmp); 
			DELETEPI(Tmp); 
			DELETEPI(Htmp); 
			PINSERTPI(j, A, &Qptr, 0); 
			FREEMPI(A); 
		} 
		DELETEPI(F); 
		FREEMPI(G); 
		return (Qptr); 
	} 
} 
 
POLYI MODPI(POLYI Fptr, POLYI Gptr) 
/* 
 * Pseudo-division of polynomials: see Knuth, Vol 2, p.407  
 * and H. Flanders, Scientific Pascal, p.510. 
 * NOTE: This returns a polynomial that is a POSITIVE multiple of the true remainder. 
 * i.e. The sign of the remainder is correct.  
 */ 
{ 
	POLYI F, Tmp, Htmp, CURSOR; 
	int j, d, degDiff; 
	MPI *A, *G, *Temp1I, *Temp2I; 
 
	d = DEGREEPI(Gptr); /* n */ 
	j = DEGREEPI(Fptr) - d; /* m - n */ 
	degDiff=j; 
	F = COPYPI(Fptr);	 
	if (j < 0) 
		return (F); 
	else 
	{ 
		G = LEADPI(Gptr); 
		A = POWERI(G, (unsigned int)(j + 1)); 
		Tmp = F; 
		F= SCALARPI(A, Tmp); 
		FREEMPI(A); 
		DELETEPI(Tmp); 
		while ((j = DEGREEPI(F)) >= d) 
		{ 
			j = j - d; 
			A = LEADPI(F); 
			if (!EQONEI(G)) 
			{ 
				Temp2I = A; 
				A = INTI(A, G); 
				FREEMPI(Temp2I); 
			} 
			Htmp = COPYPI(Gptr); 
			CURSOR = Htmp; 
			do 
			{ 
				CURSOR->DEG = j + CURSOR->DEG; 
				Temp1I = CURSOR->COEF; 
				CURSOR->COEF = MINUSI(CURSOR->COEF); 
				FREEMPI(Temp1I); 
				Temp1I = CURSOR->COEF; 
				CURSOR->COEF = MULTI(CURSOR->COEF, A); 
				FREEMPI(Temp1I); 
				CURSOR = CURSOR->NEXT; 
			} 
			while (CURSOR != NULL); 
			Tmp = F; 
			F= ADDPI(Tmp, Htmp); 
			DELETEPI(Tmp); 
			DELETEPI(Htmp); 
			FREEMPI(A); 
		} 
		 
		if ((degDiff % 2 == 0) && G->S == -1) { 
		  POLYI TMPI; 
		  TMPI = F; 
		  F = MINUSPI(F); 
		  DELETEPI(TMPI); 
		  }	 
		FREEMPI(G); 
		return (F); 
	} 
} 
 
MPI *CONTENTPI(POLYI Pptr) 
/* 
 * *Cptr is the (positive) content of the polynomial Pptr. 
 */ 
{ 
	POLYI CURSOR; 
	MPI *TempI, *Cptr; 
 
	if (Pptr == NULL) 
		return (ZEROI()); 
	else if (Pptr->DEG == 0) 
	{ 
		Cptr = COPYI(Pptr->COEF); 
		if (Cptr->S == -1) 
			Cptr->S = 1; 
		return (Cptr); 
	} 
	else 
	{ 
		CURSOR = Pptr; 
		Cptr = COPYI(CURSOR->COEF); 
		if (CURSOR->NEXT != NULL) 
		{ 
			do 
			{ 
				TempI = Cptr; 
				Cptr = GCD(Cptr, (CURSOR->NEXT)->COEF); 
				FREEMPI(TempI); 
				CURSOR = CURSOR->NEXT; 
			} 
			while (CURSOR->NEXT != NULL); 
		} 
		return (Cptr); 
	} 
} 
 
MPI *CONTENTPI2(POLYI Pptr) 
/* Returns content of Pptr such that content(Pptr)*primitive(Pptr) = Pptr */ 
{ 
  MPI *C, *C2, *L, *Z=ZEROI(); 
  C = CONTENTPI(Pptr); 
  L=LEADPI(Pptr); 
  if (COMPAREI(L,Z) < 0 && COMPAREI(C,Z) > 0) { 
    C2 = MINUSI(C); 
    FREEMPI(C); 
    FREEMPI(L); 
    FREEMPI(Z); 
    return C2; 
  } else { 
    FREEMPI(L); 
    FREEMPI(Z); 
    return C; 
  } 
} 
     
     
POLYI PRIMITIVEPI(POLYI Pptr) 
/* 
 * returns the primitive part of the polynomial Pptr. 
 * leading coefficient is positive. 
 */ 
{ 
	POLYI Tmp, Sptr, CURSOR; 
	MPI *C, *TempI; 
 
	if (Pptr == NULL) 
		return (NULL); 
	else 
	{ 
		Sptr = COPYPI(Pptr); 
		C = CONTENTPI(Sptr); 
		if ((Sptr->COEF)->S == -1) 
		{ 
			Tmp = Sptr; 
			TempI = MINUS_ONEI(); 
			Sptr = SCALARPI(TempI, Tmp); 
			FREEMPI(TempI); 
			DELETEPI(Tmp); 
		} 
		CURSOR = Sptr; 
		while (CURSOR != NULL) 
		{ 
			TempI = CURSOR->COEF; 
			CURSOR->COEF = INT(CURSOR->COEF, C); 
			FREEMPI(TempI); 
			CURSOR = CURSOR->NEXT; 
		} 
		FREEMPI(C); 
		return (Sptr); 
	} 
} 
 
POLYI GCDPI(POLYI Pptr, POLYI Qptr) 
/* 
 * returns the gcd of polynomials Pptr and Qptr. 
 * see Knuth, Vol 2, p.403-408 and H. Flanders, Scientific Pascal, p.510. 
 */ 
{ 
	POLYI Ptmp, Qtmp, Rtmp, Sptr; 
	MPI *D, *P, *Q, *TempI; 
	int j; 
	 
	if (Qptr == NULL) 
	{ 
		if (Pptr == NULL) 
			return (NULL); 
		else 
			return (COPYPI(Pptr)); 
	} 
	if (Pptr == NULL) 
	{ 
		if (Qptr == NULL) 
			return (NULL); 
		else 
			return (COPYPI(Qptr)); 
	} 
	P = CONTENTPI(Pptr); 
	Q = CONTENTPI(Qptr); 
	D = GCD(P, Q); 
	FREEMPI(P); 
	FREEMPI(Q); 
	Ptmp = PRIMITIVEPI(Pptr); 
	Qtmp = PRIMITIVEPI(Qptr); 
        j = DEGREEPI(Qtmp); 
	while ((Qtmp != NULL) && ((j = DEGREEPI(Qtmp)) != 0)) 
	{ 
		Rtmp =	MODPI(Ptmp, Qtmp); 
		DELETEPI(Ptmp); 
		Ptmp = Qtmp; 
		Qtmp = PRIMITIVEPI(Rtmp); 
		DELETEPI(Rtmp); 
	} 
	if (j == 0) 
	{ 
		TempI = Qtmp->COEF; 
		Qtmp->COEF = ONEI(); 
		FREEMPI(TempI); 
	} 
	else/* Qtmp = NULL*/ 
		Qtmp = COPYPI(Ptmp); 
	Sptr = SCALARPI(D, Qtmp); 
	FREEMPI(D); 
	DELETEPI(Ptmp); 
	DELETEPI(Qtmp); 
	return (Sptr); 
} 
 
POLYI DERIVPI(POLYI Pptr) 
/* 
 * returns the derivative of a polynomial. 
 */ 
{ 
	POLYI CURSOR, Sptr; 
	MPI *TempI; 
 
	if (DEGREEPI(Pptr) == 0) 
		return (NULL); 
	else 
	{ 
		Sptr = COPYPI(Pptr); 
  		CURSOR = Sptr; 
		while (CURSOR != NULL) 
		{ 
			TempI = CURSOR->COEF; 
			CURSOR->COEF = MULT_I(CURSOR->COEF, CURSOR->DEG); 
			FREEMPI(TempI); 
			CURSOR->DEG = CURSOR->DEG - 1; 
			if (CURSOR->NEXT == NULL) 
				break; 
			else if ((CURSOR->NEXT)->DEG == 0) 
			{ 
				DELETEPI(CURSOR->NEXT); 
				CURSOR->NEXT = NULL; 
				break; 
			} 
			else 
				CURSOR = CURSOR->NEXT; 
		} 
		return (Sptr); 
	} 
} 
 
POLYI *SQUAREFREEPI(POLYI Pptr, USI **D, USI *tptr) 
/* 
 * returns the "squarefree decomposition" of Pptr, a non-constant polynomial: 
 * Pptr = G[0]^D[0]...G[*tpr - 1]^D[*tptr - 1], 
 * where G[i] is squarefree and is the product of the irreducible factors of 
 * multiplicity D[i]. See L. Childs, Introduction to Higher Algebra, p.159. 
 */ 
{ 
	POLYI Ttmp, Ttmp1, Dtmp, Ftmp, Gtmp, Htmp, Ptmp, *G; 
	unsigned int i = 1, j = 0, n; 
 
	n = (unsigned int)(Pptr->DEG); 
	Ptmp = PRIMITIVEPI(Pptr); 
	Ftmp = DERIVPI(Ptmp); 
	Dtmp = GCDPI(Ptmp, Ftmp); 
	G = (POLYI *)mmalloc(n * sizeof(POLYI)); 
	*D = (unsigned int *)mmalloc(n * sizeof(unsigned int)); 
	if (DEGREEPI(Dtmp) == 0) 
	{ 
		G[j] = Ptmp; 
		(*D)[j] = i; 
		j++; 
		DELETEPI(Ftmp); 
		DELETEPI(Dtmp); 
		*tptr = j; 
		return (G); 
	} 
	else 
	{ 
		Gtmp = DIVPI(Ptmp, Dtmp); 
		while (DEGREEPI(Dtmp)) 
		{ 
			DELETEPI(Ptmp); 
			DELETEPI(Ftmp); 
			Htmp = Gtmp; 
			Ptmp = Dtmp; 
			Ftmp = DERIVPI(Ptmp); 
			Dtmp = GCDPI(Ptmp, Ftmp); 
			Gtmp = DIVPI(Ptmp, Dtmp); 
			Ttmp = DIVPI(Htmp, Gtmp); 
			DELETEPI(Htmp); 
			Ttmp1 = PRIMITIVEPI(Ttmp); 
			if (Ttmp1->DEG > 0) 
			{ 
				G[j] = COPYPI(Ttmp1); 
				(*D)[j] = i; 
				j++; 
			} 
			DELETEPI(Ttmp); 
			DELETEPI(Ttmp1); 
			i++; 
		} 
		DELETEPI(Ptmp); 
		DELETEPI(Ftmp); 
		G[j] = PRIMITIVEPI(Gtmp); 
		(*D)[j] = i; 
		j++; 
		DELETEPI(Gtmp); 
		DELETEPI(Dtmp); 
		*tptr = j; 
		return (G); 
	} 
} 
 
POLYI POWERPI(POLYI Pptr, USI n) 
/* 
 * returns Pptr ^ n, where 0 <= n < R0 * R0. 
 */ 
{ 
	POLYI B, Eptr, Tmp; 
 
	Eptr = ONEPI(); 
	if (n == 0) 
		return (Eptr); 
	B = COPYPI(Pptr); 
	while (1) 
        { 
		if (n & 1)  
		{ 
			Tmp = Eptr; 
			Eptr = MULTPI(Tmp, B); 
			DELETEPI(Tmp); 
			if (n == 1) 
			{ 
				DELETEPI(B); 
				return (Eptr); 
			} 
		} 
		Tmp = B; 
		B = MULTPI(Tmp, Tmp); 
		DELETEPI(Tmp); 
		n = n >> 1; 
	} 
} 
 
POLYI ONEPI() 
/* 
 * returns the constant polynomial 1. 
 */ 
{ 
	POLYI Pptr; 
 
	Pptr = CREATEPI(); 
	Pptr->DEG = 0; 
	Pptr->COEF = ONEI(); 
	Pptr->NEXT = NULL; 
	return (Pptr); 
} 
POLYI ZEROPI() 
     /* returns the zero polynomial */ 
{ 
  POLYI Pptr; 
  Pptr= CREATEPI(); 
  Pptr->DEG=0; 
  Pptr->COEF=ZEROI(); 
  Pptr->NEXT=NULL; 
  return (Pptr); 
} 
POLYI CONSTANTPI(MPI *Aptr) 
/* 
 * returns the constant polynomial whose constant term is *Aptr. 
 */ 
{ 
	POLYI Pptr;	 
 
	if (Aptr->S == 0) 
		return (NULL); 
	else 
	{ 
		Pptr = CREATEPI(); 
		Pptr->DEG = 0; 
		Pptr->COEF = COPYI(Aptr); 
		Pptr->NEXT = NULL; 
		return (Pptr); 
	} 
} 
 
MPI *SUBRESULTANT(POLYI Pptr, POLYI Qptr) 
/* 
 * *Aptr is the resultant of Pptr and Qptr, found using the subresultant 
 * algorithm, p. 130. E. Kaltofen, G. E. Collins etc, Algorithm 4.5. 
 * similar to Knuth, Algorithm C, p. 410. 
 */ 
{ 
	unsigned delta; 
	MPI *G, *G1, *H1, *H2, *Aptr, *TempI; 
	POLYI Utmp, Vtmp, Rtmp, CURSOR; 
 
	G = ONEI(); 
	Aptr = ONEI(); 
	Utmp = COPYPI(Pptr); 
	Vtmp = COPYPI(Qptr); 
	while (Vtmp != NULL) 
	{ 
		Rtmp = MODPI(Utmp, Vtmp); 
		if (Rtmp == NULL && DEGREEPI(Vtmp) > 0) 
		{ 
			FREEMPI(G); 
			FREEMPI(Aptr); 
			DELETEPI(Utmp); 
			DELETEPI(Vtmp); 
			return (ZEROI()); 
		} 
		delta = DEGREEPI(Utmp) - DEGREEPI(Vtmp); 
		DELETEPI(Utmp); 
		Utmp = Vtmp; 
		G1 = MINUSI(G); 
		H1 = MINUSI(Aptr); 
		TempI = H1; 
		H1 = POWERI(H1, delta); 
		FREEMPI(TempI); 
		TempI = H1; 
		H1 = MULTI(H1, G1); 
		FREEMPI(TempI); 
		CURSOR = Rtmp; 
		while (CURSOR != NULL) 
		{ 
			TempI = CURSOR->COEF; 
			CURSOR->COEF = INTI(CURSOR->COEF, H1); 
			FREEMPI(TempI); 
			CURSOR = CURSOR->NEXT; 
		} 
		Vtmp = Rtmp; 
		TempI = G; 
		G = LEADPI(Utmp); 
		FREEMPI(TempI); 
		TempI = G1; 
		G1 = POWERI(G, delta); 
		FREEMPI(TempI); 
		TempI = H1; 
		H1 = MULTI(Aptr, G1); 
		FREEMPI(TempI); 
		H2 = POWERI(Aptr, delta); 
		TempI = Aptr; 
		Aptr = INTI(H1, H2); 
		FREEMPI(TempI); 
		FREEMPI(H1); 
		FREEMPI(H2); 
		FREEMPI(G1); 
	} 
	DELETEPI(Utmp); 
	FREEMPI(G); 
	return (Aptr); 
} 
 
MPI *DISCRIMINANTPI(POLYI Pptr) 
/* 
 * *Dptr = Discriminant of Pptr = (1/a[n])*(-1)^{n*(n-1)/2 * Res(Pptr, Pptr'). 
 * See O. Perron, Algebra, Vol 1, p.212. 
 */ 
{ 
	POLYI P; 
	MPI *A, *Dptr, *TempI; 
	int n; 
 
	P = DERIVPI(Pptr); 
	Dptr = SUBRESULTANT(Pptr, P); 
	A = LEADPI(Pptr); 
	TempI = Dptr; 
	Dptr = INTI(Dptr, A); 
	FREEMPI(TempI); 
	FREEMPI(A); 
	DELETEPI(P); 
	n = (DEGREEPI(Pptr)) % 4; 
	if (n == 2 || n == 3) 
		Dptr->S = -(Dptr->S); 
	return (Dptr); 
} 
 
MPI *LENGTHSQPI(POLYI Pptr) 
/* 
 * *Cptr is the sum of the squares of the coefficients of Pptr. 
 */ 
{ 
	POLYI CURSOR; 
	MPI *C, *Cptr, *TempI; 
 
	Cptr = ZEROI(); 
	if (Pptr == NULL) 
		return (Cptr); 
	CURSOR = Pptr; 
	while (CURSOR != NULL) 
	{ 
		C = MULTI(CURSOR->COEF, CURSOR->COEF); 
		TempI =  Cptr; 
		Cptr = ADDI(C, Cptr); 
		FREEMPI(C); 
		FREEMPI(TempI); 
		CURSOR = CURSOR->NEXT; 
	} 
	return (Cptr); 
} 
 
MPI *VAL0PI(POLYI Pptr) 
/* 
 * *Mptr = Pptr(0) 
 */ 
{ 
	POLYI CURSOR; 
 
	if (Pptr == NULL) 
		return ZEROI(); 
	CURSOR = Pptr; 
	while (CURSOR->NEXT != NULL) 
		CURSOR = CURSOR->NEXT; 
	if (DEGREEPI(CURSOR) != 0) 
		return ZEROI(); 
	else 
		return COPYI(CURSOR->COEF);	 
} 
 
/* Returns respectively positive, or negative if the sign of the polynomial  
 * evaluated at the supplied rational number is positive or negative. 
 * Returns zero if polynomial has a root at the supplied rational */ 
int SIGN_AT_R_PI(POLYI P, MPR *R) 
{ 
  MPI *TMPI, *RESULT=ZEROI(), *X_TO_I, *TERM; 
  MPI *A=COPYI(R->N), *D=COPYI(R->D); 
  POLYI CURSOR=P; 
  unsigned int n=DEGREEPI(P), i; 
 
  if (P == NULL)  
    i=0; 
  else while (CURSOR) { 
    i = DEGREEPI(CURSOR); 
    TERM=POWERI(A, i); 
     
    TMPI=TERM; 
    TERM=MULTI(CURSOR->COEF, TERM); 
    FREEMPI(TMPI); 
     
    X_TO_I=POWERI(D, n-i); 
     
    TMPI=TERM; 
    TERM=MULTI(TERM, X_TO_I); 
    FREEMPI(TMPI); 
    FREEMPI(X_TO_I); 
 
    TMPI=RESULT; 
    RESULT=ADDI(RESULT, TERM); 
    FREEMPI(TMPI); 
    FREEMPI(TERM); 
 
    CURSOR=CURSOR->NEXT; 
  } 
  i = SIGNI(RESULT); /* shouldn't really use this as return val but it works */ 
  FREEMPI(RESULT); 
  FREEMPI(A); 
  FREEMPI(D); 
  return i; 
} 
 
/* If P = p(x) then this function returns p(-x) */ 
POLYI P_OF_NEG_X(POLYI P) 
{ 
  POLYI Q=COPYPI(P); 
  POLYI CURSOR=Q; 
  while (CURSOR) { 
    if (DEGREEPI(CURSOR)%2 == 1) /* if odd degree */ 
      CURSOR->COEF->S = - CURSOR->COEF->S; 
    CURSOR=CURSOR->NEXT; 
  } 
  return Q; 
} 
 
/* Returns -1*P(x) */ 
POLYI MINUSPI(POLYI P) 
{ 
  POLYI Q=COPYPI(P); 
  POLYI CURSOR=Q; 
  while (CURSOR) { 
    CURSOR->COEF->S = -CURSOR->COEF->S; 
    CURSOR=CURSOR->NEXT; 
  } 
  return Q; 
} 
 
/* Modifies the supplied polynomial so that p(x) = p(x+A) */ 
 
void P_OF_X_PLUS(POLYI *P, MPI *A) 
{ 
  MPI *ZERO = ZEROI(); 
  MPIA COEF = BUILDMPIA(); 
  POLYI CURSOR = *P; 
  int i, j,  n = DEGREEPI(*P); 
 
  for (i=n; i >=0; i--) { 
	ADD_TO_MPIA(COEF, ZERO, i); 
  } 
  while (CURSOR) { 
    ADD_TO_MPIA(COEF, CURSOR->COEF, DEGREEPI(CURSOR)); 
    CURSOR=CURSOR->NEXT; 
  } 
 
  for (i=0; i <= n-1; i++) 
    for (j = n-1;j >= i; j--) { 
      MPI *TMP, *MUL; 
      MUL = MULTI(A, COEF->A[j+1]); 
      TMP = COEF->A[j]; 
      COEF->A[j] = ADDI(MUL, COEF->A[j]); 
      FREEMPI(TMP); 
      FREEMPI(MUL); 
    } 
   
  DELETEPI(*P); 
  *P = NULL; 
  for (i=0; i <= n; i++) 
    PINSERTPI(i, COEF->A[i], P, 0); 
  PURGEPI(P); 
  FREEMPIA(COEF); 
  FREEMPI(ZERO); 
} 
     
POLYI PRIMITIVEPI_(POLYI Pptr) 
/* 
 * returns the primitive part of the polynomial Pptr. 
 * retaining the sign of the leading coefficient. 
 */ 
{ 
	POLYI Sptr, CURSOR; 
	MPI *C, *TempI; 
 
	if (Pptr == NULL) 
		return (NULL); 
	else 
	{ 
		Sptr = COPYPI(Pptr); 
		C = CONTENTPI(Sptr); 
		CURSOR = Sptr; 
		while (CURSOR != NULL) 
		{ 
			TempI = CURSOR->COEF; 
			CURSOR->COEF = INT(CURSOR->COEF, C); 
			FREEMPI(TempI); 
			CURSOR = CURSOR->NEXT; 
		} 
		FREEMPI(C); 
		return (Sptr); 
	} 
}