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


/* program:  "i2.c" */ 
/* 
 * A translation into C of the long division section of pascal program 
 * ARITHMETIC,  from "SCIENTIFIC PASCAL" by H. FLANDERS pp. 342-357. 
 */ 
 
#include  
#include  
#include "integer.h" 
#include "fun.h" 
	 
unsigned long l0, n0, bn, bn1; 
 
void INIT(MPI *Aptr, MPI *Bptr, MPI **A1ptr, MPI **B1ptr) 		 
/* 
 * see lemmas 2 and 3, pp. 349-350.  
 * input: Aptr, Bptr are pointers to MPI'S, Aptr->D >=  Bptr->D = n0 >= 1. 
 *  output: l0 = int[R0 / (Bptr->V[n0] + 1), *A1ptr = l0 * *Aptr, 
 * *B1ptr = l0 * *Bptr, bn = B1ptr->V[n0], bn1 = B1ptr->V[n0 - 1]. 
 */ 
{ 
	n0 = Bptr->D; 
	l0 = R0 / (Bptr->V[n0] + 1); 
	if (l0 > 1) 
	{ 
		*A1ptr = MULT_I(Aptr,(long)(l0)); 
		*B1ptr = MULT_I(Bptr,(long)(l0)); 
	} 
	else 
	{ 
		*A1ptr = COPYI(Aptr); 
		*B1ptr = COPYI(Bptr); 
	} 
	bn = (*B1ptr)->V[n0]; 
	bn1 = (*B1ptr)->V[n0 - 1]; 
	return; 
} 
 
unsigned long qp; 
void FIND(unsigned int k, MPI *A1ptr, MPI *B1ptr, unsigned long R[]) 
/* 
 * finds the k-th trial quotient digit qp = Q' using lemmas 1-4.  
 */ 
{ 
	unsigned long t, u, rp; 
 
	if (k == A1ptr->D - B1ptr->D) 
		R[A1ptr->D + 1] = 0; /* an extra 0 is added to the front of 
			the initial dividend to ensure qp < R0.(see p348) */ 
	 
	u = (R[k + B1ptr->D + 1] << T0) + R[k + B1ptr->D]; 
	t = u / bn; 
	if (t < R0) 
		qp = t; 
	else 
		qp = R0 - 1; 
 
	rp = u - qp * bn; /* Flanders erroneously has t instead of qp */  
	 
	if (rp >= R0) /* rp * R0 is then >= 2 ^ O32 > bn1 * qp. */ 
		return; 
	while (bn1 * qp > (rp << T0) + R[k + n0 - 1]) 
	{	/* see lemma 4(1) */  
		qp--; 
		rp = rp + bn; 
		if (rp >= R0) /* rp * R0 is then >= 2 ^ O32 > bn1 * qp. */ 
			return; 
	} 
	return; 
} 
 
void NEXT(int k, MPI *A1ptr, MPI *B1ptr, unsigned long R[]) 
/* 
 * the run of n0 + 1 "digits" in the current remainder, from 
 * the (k + n0 + 1)-th down to the k-th, is divided by *B1ptr. The quotient 
 * becomes the k-th "digit" of *Qptr in INT0() and the remainder R is updated. 
 */ 
{ 
	long l; 
	unsigned int j; 
	unsigned long t, ct = 0, cr = 1;	/* initialize "carries */ 
	 
	for (j = 0; j <= n0; j++) 
	{	/* multiply with carry */ 
		t = (B1ptr->V[j]) * qp + ct; 
		ct = t >> T0; 
		t = t & (R0 - 1); 	/* digit to subract with carry */ 
		t = R[k + j] - t + R0 + cr - 1; 
		R[k + j] = t & (R0 - 1); 
		cr = t >> T0; 
	} 
	if (k == A1ptr->D - B1ptr->D) 
		R[A1ptr->D + 1] = 0; /* avoids garbage value for R[k + n0 + 1] */ 
	l = R[k + n0 + 1] - ct + cr - 1; 
	if (l < 0) { /* qp is one too large */ 
		qp--; 
		cr = 0;  
		for (j = 0; j <= n0; j++) 
		{ /* add *B1ptr back */ 
			t = R[k + j] + B1ptr->V[j] + cr; 
			R[k + j] = t & (R0 - 1); 
			cr = t >> T0; 
		} 
		R[k + n0 + 1] = l + cr; 
	} 
	return; 
	 
} 
 
 
MPI *INT0_(MPI *Aptr, unsigned long b) 
/* 
 * input: Aptr is a pointer to an non-negative MPI, b is a positive integer, 
 * b < R0. output:  *Qptr = int(*Aptr / b). 
 */ 
{ 
	unsigned int k, n; 
	unsigned long t; 
	MPI *Qptr, *tmp; 
 
	if (b >= R0) 
	{ 
		fprintf(stderr, "in INT0_I, %lu >= R0\n", b); 
		exit(1); 
	} 
	Qptr = COPYI(Aptr); 
	n = Qptr->D; 
	t = Qptr->V[Qptr->D]; 
	if (Qptr->D != 0) 
	{ 
		for (k = Qptr->D; k >= 1; k--) 
		{ 
			Qptr->V[k] = t / b; 
			t  = Qptr->V[k - 1] + ((t % b) << T0); 
		} 
		if (Qptr->V[Qptr->D] == 0) 
		{ 
			 
			tmp = BANK_REALLOC(Qptr, n - 1); 
			FREEMPI(Qptr); 
			Qptr = tmp; 
			/* we remark that Qptr->S = 1 here. */ 
		} 
	} 	 
	Qptr->V[0] = t / b; 
	if (Qptr->D == 0)  
		Qptr->S = Qptr->V[0] ? 1 : 0; 
	return Qptr; 
} 
 
unsigned long MOD0_(MPI *Aptr, unsigned long b) 
/* 
 * input: Aptr is a pointer to a non-negative MPI, b is a positive integer, 
 * b < R0.  output: *Aptr mod b. 
 */ 
{ 
	MPI *R; 
	unsigned int k; 
	unsigned long t; 
	if (b >= R0) 
	{ 
		fprintf(stderr, "in MOD0_, %lu >= R0\n", b); 
		exit(1); 
	} 
	R = COPYI(Aptr); 
	t = R->V[R->D]; 
	if (R->D != 0) 
	{ 
		for (k = R->D; k >= 1; k--) 
		{ 
			R->V[k] = t / b; 
			t  = R->V[k - 1] + ((t % b) << T0); 
		} 
	} 	 
 
	FREEMPI(R); 
	return (t % b); 
} 
 
MPI *INT_(MPI *Aptr, unsigned long b) 
/* 
 * input: Aptr is a pointer to an MPI, b is a positive integer, b < R0. 
 * output:  *Qptr = int(*Aptr, b). 
 */ 
{ 
	MPI *Q, *Qptr; 
	unsigned long r; 
 
	if (b >= R0) 
	{ 
		fprintf(stderr, "in INT_, %lu >= R0\n", b); 
		exit(1); 
	} 
	if (Aptr->S >= 0) 
		return (INT0_(Aptr, b)); 
	else 
	{ 
		Aptr->S =  1; 
		Q = INT0_(Aptr, b); 
		r = MOD0_(Aptr, b); 
		Aptr->S = -1; 
		/* -*Aptr = *Q * b + r, 0 <= r < b, 
				*Aptr = (-*Q - 1) * b + b - r */ 
		if (r) 
		{/* add 1 to |*Q|, but not changing the sign of *Q */ 
			Qptr = ADD0_I(Q, (USL)1); 
			Qptr->S = -1; 
			FREEMPI(Q); 
			return Qptr; 
		} 
		else 
		{					/* r = 0 here */ 
			Q->S = -1; 
			Qptr = COPYI(Q); 
			FREEMPI(Q); 
			return Qptr;				 
		} 
	} 
} 
 
unsigned long MOD_(MPI *Aptr, unsigned long b) 
/* 
 * input: Aptr is a pointer to an MPI, b is a positive integer, b < R0. 
 * output: *Aptr mod b. 
 */ 
{ 
	unsigned long r; 
 
	if (b >= R0) 
	{ 
		fprintf(stderr, "in MOD_, %lu >= R0\n", b); 
		exit(1); 
	} 
	if (Aptr->S >= 0) 
		return (MOD0_(Aptr, b)); 
	else 
	{ 
		Aptr->S =  1; 
		r = MOD0_(Aptr, b); 
		Aptr->S = -1; 
		/* -*Aptr = *Q * b + r, 0 <= r < b, 
				*Aptr = (-*Q - 1) * b + b - r */ 
		if (r)  
			return (b - r); 
		else 
			return (0);				 
	} 
} 
 
MPI *INT0(MPI *Aptr, MPI *Bptr) 
/* 
 * input: Aptr, Bptr, pointers to non-negative MPI'S, *Bptr > 0. 
 * output: *Qptr = int(*Aptr / *Bptr), *Rptr = *Aptr mod *Bptr. 
 */ 
{ 
	MPI *A1, *B1, *Qptr, *tmp; 
	int k; 
	unsigned int e, f, degree; 
	unsigned long *R; 
 
	if (Bptr->D == 0) 
		return (INT0_(Aptr, Bptr->V[0])); 
	if (Aptr->D < Bptr->D) 
		return ZEROI(); 
	INIT(Aptr, Bptr, &A1, &B1); 
	f = 2 + A1->D; 
	R = (unsigned long *)mmalloc((USL)(f * sizeof(unsigned long))); 
	/* we malloc an extra place needed in FIND(). */ 
	for (k = 0; k <= A1->D; k++) 
		R[k] = A1->V[k]; 
	e = A1->D - B1->D; 
	Qptr = BUILDMPI(e + 1); 
	for (k = e; k >= 0; k--) 
	{ 
		FIND((unsigned int) k, A1, B1, R); 
		NEXT(k, A1, B1, R); 
		Qptr->V[k] = qp; 
	} 
	ffree((char *)R, f * sizeof(unsigned long)); 
	Qptr->S = 0;			/* finding Qptr->S and Qptr->D */ 
	degree = 0; 
	k = e; 
	FREEMPI(A1); 
	FREEMPI(B1); 
	while (k >= 0) 
	{ 		   	 
		if (Qptr->V[k] != 0) 
		{ 
			Qptr->S = 1; 
			degree = k; 
			k = -1; 
		} 
		else 
			k--; 
	} 							 
	tmp = Qptr; 
	Qptr = BANK_REALLOC(Qptr, degree); 
	FREEMPI(tmp); 
	return Qptr; 
} 
 
MPI *MOD0(MPI *Aptr, MPI *Bptr) 
/* 
 * input: Aptr, Bptr, pointers to MPI'S, *Aptr >= 0, *Bptr > 0. 
 * output: *Rptr = *Aptr mod *Bptr. 
 */ 
{ 
	MPI *A1, *B1, *Rptr, *Temp; 
	int k, s;  
	unsigned int d, e, f; 
	unsigned long *R; 
 
	if (Bptr->D == 0) 
	{ 
		Rptr = BUILDMPI(1); 
		Rptr->V[0] = MOD0_(Aptr, Bptr->V[0]); 
		Rptr->S = Rptr->V[0] ? 1 : 0; 
 
		return Rptr; 
	} 
	if (Aptr->D < Bptr->D) 
		return COPYI(Aptr); 
	INIT(Aptr, Bptr, &A1, &B1); 
	f = 2 + A1->D; 
	R = (unsigned long *)mmalloc((USL)(f * sizeof(unsigned long))); 
	/* we malloc an extra place needed in FIND(). */ 
	for (k = 0; k <= A1->D; k++) 
		R[k] = A1->V[k]; 
	e = A1->D - B1->D; 
	for (k = e; k >= 0; k--) 
	{ 
		FIND((unsigned int) k, A1, B1, R); 
		NEXT(k, A1, B1, R); 
	} 
	FREEMPI(A1); 
	FREEMPI(B1); 
 
	/* finding Rptr->S and Rptr->D */ 
 
	s = 0; 
	d = 0; 
	k = n0; 
	while (k >= 0) 
	{ 
		if (R[k] != 0) 
		{ 
			s = 1; 
			d = k; 
			k = -1; 
		} 
		else 
			k--; 
	} 
	Rptr = BUILDMPI(1 + d); 
	Rptr->S = s; 
	for (k = 0; k <= Rptr->D; k++) 
		Rptr->V[k] =  R[k]; 
	ffree((char *)R, f*sizeof(unsigned long)); 
	Temp = Rptr; 
	Rptr = INT0_(Temp, l0);			 
	FREEMPI(Temp);	 
 
	return Rptr; 
} 
 
MPI *INT(MPI *Aptr, MPI *Bptr) 
/* 
 * input: Aptr, Bptr, pointers to MPI'S, *Bptr > 0, 
 * output: MPI *Qptr = int(*Aptr, *Bptr). 
 */ 
{ 
	MPI *Q, *R, *Qptr; 
 
	if (Bptr->D == 0) 
		return	INT_(Aptr, Bptr->V[0]); 
	if (Aptr->S >= 0) 
		return INT0(Aptr, Bptr); 
	else 
	{ 
		Aptr->S =  1; 
		Q = INT0(Aptr, Bptr); 
		R = MOD0(Aptr, Bptr); 
		Aptr->S = -1; 
		/* -*Aptr = *Q * *Bptr + *R, 0 <= *R < *Bptr, 
				*Aptr = (-*Q - 1) * *Bptr + *Bptr - R */ 
		if (R->S == 1) 
		{/* add 1 to |*Q|, but not changing the sign of *Q */ 
			Qptr = ADD0_I(Q, (USL)1); 
			Qptr->S = -1; 
		} 
		else 
		{					/* *R = 0 here */ 
			Q->S = -1; 
			Qptr = COPYI(Q); 
		} 
		FREEMPI(Q); 
		FREEMPI(R); 
		return Qptr; 
	} 
} 
 
MPI *INTI(MPI *Aptr, MPI *Bptr) 
/* 
 * input: Aptr, Bptr, pointers to MPI'S, *Bptr != 0, 
 * output: MPI *Qptr = int(*Aptr, *Bptr). 
 */ 
{ 
	MPI *A, *B, *Qptr; 
 
	if (Bptr->S > 0) 
		return INT(Aptr, Bptr); 
	else 
	{ 
			A = COPYI(Aptr); 
		B = COPYI(Bptr); 
		A->S = -(A->S); 
		B->S = -(B->S); 
		Qptr = INT(A, B); 
		FREEMPI(A); 
		FREEMPI(B); 
		return Qptr; 
		} 
} 
 
MPI *MOD(MPI *Aptr, MPI *Bptr) 
/* 
 * input: Aptr, Bptr, pointers to MPI'S, *Bptr > 0. 
 * output: MPI *Rptr = *Aptr mod *Bptr. 
 */ 
{ 
	MPI *R, *Rptr; 
 
	if (Bptr->D == 0) 
		return CHANGE(MOD_(Aptr, Bptr->V[0])); 
	if (Aptr->S >= 0) 
		return 	MOD0(Aptr, Bptr); 
	else 
	{ 
		Aptr->S = 1; 
		R = MOD0(Aptr, Bptr); 
		Aptr->S = -1; 
		/* -*Aptr = *Q * *Bptr + *R, 0 <= *R < *Bptr, 
				*Aptr = (-*Q - 1) * *Bptr + *Bptr - *R */ 
		if (R->S == 1) 
			Rptr = SUB0I(Bptr, R); 
		else 
			Rptr = ZEROI(); 
		FREEMPI(R); 
		return Rptr;				 
	} 
} 
 
unsigned long MODINT0_(MPI *Aptr, unsigned long b, MPI **Qptr) 
/* 
 * input: Aptr is a pointer to an non-negative MPI, b is a positive integer, 
 * b < R0. output: *Aptr (mod b) and *Qptr = int(*Aptr / b). 
 */ 
{ 
	unsigned int k, n; 
	unsigned long t; 
	MPI *tmp; 
 
	if (b >= R0) 
	{ 
		fprintf(stderr, "in MODINT0_, %lu >= R0\n", b); 
		exit(1); 
	} 
	*Qptr = COPYI(Aptr); 
	n = (*Qptr)->D; 
	t = (*Qptr)->V[(*Qptr)->D]; 
	if ((*Qptr)->D != 0) 
	{ 
		for (k = (*Qptr)->D; k >= 1; k--) 
		{ 
			(*Qptr)->V[k] = t / b; 
			t  = (*Qptr)->V[k - 1] + ((t % b) << T0); 
		} 
		if ((*Qptr)->V[(*Qptr)->D] == 0) 
		{ 
			 
			tmp = BANK_REALLOC(*Qptr, n - 1); 
			FREEMPI(*Qptr); 
			*Qptr = tmp; 
			/* we remark that (*Qptr)->S = 1 here. */ 
		} 
	} 	 
	(*Qptr)->V[0] = t / b; 
	if ((*Qptr)->D == 0)  
		(*Qptr)->S = (*Qptr)->V[0] ? 1 : 0; 
	return (t % b); 
} 
 
MPI *HALFMOD(MPI *Aptr, MPI *Pptr) 
/* Returns R=Aptr(mod Pptr) if R <= Pptr/2, otherwise R-Pptr. */ 
{ 
	MPI *T, *U, *W; 
	int t; 
 
	T = MOD(Aptr, Pptr); 
	W = MULT_II(T, 2); 
	t = RSV(W, Pptr); 
	FREEMPI(W); 
	if (t == 1) 
		U = SUBI(T, Pptr); 
	else 
		U = COPYI(T); 
	FREEMPI(T); 
	return (U); 
} 
 
MPI *HALFMODX(MPI *Aptr, MPI *Pptr) 
/* Returns R=Aptr(mod Pptr) if R <= Pptr/2, otherwise R-Pptr. */ 
{ 
	if(Pptr->S <= 0){ 
		printf("N <= 0\n"); 
		return(NULL); 
	} 
	else 
		return(HALFMOD(Aptr, Pptr)); 
} 
 
MPI *CEILINGI(MPI *A, MPI *B) 
/* Returns the least integer not less than A/B. */ 
{ 
	MPI *X, *TMP, *TMP1; 
	USI t; 
 
	X = INTI(A, B); 
	TMP = MULTI(X, B); 
	t = EQUALI(TMP, A); 
	FREEMPI(TMP); 
	if (t) 
		return (X); 
	else{ 
		TMP = ONEI(); 
		TMP1 = ADDI(X, TMP); 
		FREEMPI(TMP); 
		FREEMPI(X); 
		return(TMP1); 
	} 
} 
 
MPI *CEILINGIX(MPI *A, MPI *B) 
{ 
	if(B->S == 0){ 
		printf("B = 0\n"); 
		return(NULL); 
	} 
	else 
		return(CEILINGI(A, B)); 
} 
 
MPI *NEARINT(MPI *M, MPI *N){ 
/* Returns Z, the nearest integer to M/N, 
 * with Z=T if M/N=1/2+T. 
 */ 
	MPI *TEMP1, *TEMP2, *R; 
	 
	R = HALFMOD(M, N); 
	TEMP1 = SUBI(M, R); 
	TEMP2 = INT(TEMP1, N); 
	FREEMPI(R); 
	FREEMPI(TEMP1); 
	return(TEMP2); 
} 
 
MPI *NEARINTX(MPI *M, MPI *N){ 
/* Returns Z, the nearest integer to M/N, 
 * with Z=T if M/N=1/2+T. 
 */ 
	if(N->S <= 0){ 
		printf("N <= 0\n"); 
		return(NULL); 
	} 
	else 
		return(NEARINT(M, N)); 
} 
 
void POWERD(MPI *A, MPI *B, MPI *D, MPI *N, MPI **AA, MPI **BB){ 
/* *A + *B\sqrt(D)=(A + \sqrt(D))^N  */ 
    MPI *Y, *TEMP, *TEMP1, *TEMP2, *TEMP3, *TEMP4, *TEMP5; 
    MPI *X1, *X2, *T2; 
 
   X1 = COPYI(A); 
   X2 = COPYI(B); 
   Y = COPYI(N); 
   *AA = ONEI(); 
   *BB = ZEROI(); 
   while(Y->S){ 
      while((Y->V[0])%2 == 0){ 
          TEMP = Y; 
          Y = INT_(Y, 2); 
          FREEMPI(TEMP); 
          TEMP = X1; 
          TEMP1 = MULTI(X2, X2); 
          TEMP2 = MULTI(X1, X1); 
          TEMP3 = MULTI(D, TEMP1); 
          FREEMPI(TEMP1); 
          X1 = ADDI(TEMP2, TEMP3); 
          FREEMPI(TEMP2); 
          FREEMPI(TEMP3); 
          TEMP4 = MULTI(TEMP, X2); 
          FREEMPI(TEMP); 
          T2 = X2; 
          X2 = MULT_I(TEMP4, 2); 
          FREEMPI(TEMP4); 
          FREEMPI(T2); 
      } 
      TEMP = Y; 
      Y = SUB0_I(Y, 1); 
      FREEMPI(TEMP); 
      TEMP = *AA; 
      TEMP1 = MULTI(*BB, X2); 
      TEMP2 = MULTI(*AA, X1); 
      TEMP3 = MULTI(D, TEMP1); 
      FREEMPI(TEMP1); 
      *AA = ADDI(TEMP2, TEMP3); 
      FREEMPI(TEMP2); 
      FREEMPI(TEMP3); 
      TEMP4 = MULTI(TEMP, X2); 
      FREEMPI(TEMP); 
      TEMP5 = MULTI(*BB, X1); 
      T2 = *BB; 
      *BB = ADDI(TEMP4, TEMP5); 
      FREEMPI(T2); 
      FREEMPI(TEMP4); 
      FREEMPI(TEMP5); 
   } 
   FREEMPI(Y); 
   FREEMPI(X1); 
   FREEMPI(X2); 
   return; 
}