www.pudn.com > calc.rar > p-adic.c


#define _CRT_SECURE_NO_DEPRECATE 
#include "integer.h" 
#include  
#include  
#include  
#include "fun.h" 
#include "stack.h" 
/*#include "unistd.h"*/ 
 
/* MULT_PADIC forms the product of a=a[0]+a[1]p+...+a[m]p^m  
 * and b=b[0]+b[1]p+...+b[n]p^n, where a[m] and b[n] are nonzero. 
 * The output is prod[0]+prod[1]p+...+prod[l]p^l, where prod[l] is nonzero. 
 * If a or b is zero, we return 0 at the start, otherwise return l. 
 * The program is an adaption of one in i1.c 
 * from http://www.numbertheory.org/calc/ 
 */ 
void MULT_PADIC(MPIA A, MPIA B, MPI *P, MPIA *PROD, USI m, USI n, USI *l){ 
	MPI *C, *T, *TEMP, *TEMP1, *TEMP2, *BK; 
	USI j, k, temp; 
 
	*PROD = BUILDMPIA(); 
	if((m == 0 && EQZEROI(A->A[0])) || (n == 0 && EQZEROI(B->A[0]))){ 
		TEMP = ZEROI(); 
		ADD_TO_MPIA(*PROD, TEMP, 0); 
		FREEMPI(TEMP); 
		*l = 0; 
		return; 
        } 
	C = ZEROI(); 
	*l = m + n + 1; 
	for(k = 0; k <= m; k++){ 
		TEMP = ZEROI(); 
		ADD_TO_MPIA(*PROD, TEMP, k); 
		FREEMPI(TEMP); 
	} 
	for(k = 0; k <= n; k++){ 
		BK = B->A[k]; 
		if(EQZEROI(BK) == 0){ 
			TEMP = C; 
			C = ZEROI(); 
			FREEMPI(TEMP); 
			for(j = 0; j <= m; j++){ 
				temp = j + k; 
				TEMP1 = MULTI(A->A[j], BK); 
				TEMP2 = ADDI(TEMP1, (*PROD)->A[temp]); 
				T = ADDI(TEMP2, C); 
				TEMP = MOD(T, P); 
				ADD_TO_MPIA(*PROD, TEMP, temp); 
				FREEMPI(TEMP); 
				FREEMPI(TEMP1); 
				FREEMPI(TEMP2); 
				TEMP = C; 
				C = INT0(T, P); 
				FREEMPI(TEMP); 
				FREEMPI(T); 
			} 
			temp = m + k + 1; 
			TEMP= COPYI(C); 
			ADD_TO_MPIA(*PROD, TEMP, temp); 
			FREEMPI(TEMP); 
		}else{ 
			temp = m + k + 1; 
			TEMP =  ZEROI(); 
			ADD_TO_MPIA(*PROD, TEMP, temp); 
			FREEMPI(TEMP); 
		} 
	} 
	if(EQZEROI(C)){ 
		*l = m + n; 
	} 
	FREEMPI(C); 
	return; 
} 
 
/* 
 * RSV_PADIC() is an adaption of one in i1.c 
 * from http://www.numbertheory.org/calc/ 
 * it returns 1,0,-1 according as A >,=,< B. 
 * It is assumed that A and B are to the same base. 
 */ 
int RSV_PADIC(MPIA A, MPIA B, USI m, USI n){ 
	USI j; 
	int t; 
 
	if(m > n) 
		return(1); 
	if(m < n) 
		return(-1); 
	j = m; 
	while(EQUALI(A->A[j], B->A[j]) && j){ 
		j--; 
	} 
	t = RSV(A->A[j], B->A[j]); 
	if(t > 0) 
		return(1); 
	if(t < 0) 
		return(-1); 
	return(0); 
} 
 
/* 
 * SUB0_PADIC() is an adaption of one in i1.c 
 * from http://www.numbertheory.org/calc/ 
 * Here A >= B and returns l and the array  
 * diff[]=A-B=diff[0]+diff[1]*P+...+diff[l]*P^l. 
 */ 
 
void SUB_PADIC(MPIA A, MPIA B, MPI *P, MPIA *DIFF, USI m, USI n, USI *l){ 
	USI d, j, temp;	 
	int k; 
	MPI *C, *T, *TEMP, *TEMP1, *TEMP2, *ONE; 
 
	*DIFF = BUILDMPIA(); 
	if(n == 0 && EQZEROI(B->A[0])){ 
		for(j = 0; j <= m; j++){ 
			TEMP = A->A[j]; 
			ADD_TO_MPIA(*DIFF, TEMP, j); 
			FREEMPI(TEMP); 
		} 
		*l = m; 
		return; 
	} 
	ONE = ONEI(); 
	C = ONEI(); 
	*l = m; 
	for(j = 0; j <= n; j++){ 
		TEMP = SUBI(A->A[j], B->A[j]); 
		TEMP1 = ADD0I(P, C); 
		TEMP2 = SUBI(TEMP1, ONE); 
		T = ADDI(TEMP, TEMP2); 
		FREEMPI(TEMP); 
		FREEMPI(TEMP1); 
		FREEMPI(TEMP2); 
		TEMP = MOD0(T, P); 
		ADD_TO_MPIA(*DIFF, TEMP, j); 
		FREEMPI(TEMP); 
		TEMP = C; 
		C = INT0(T, P); 
		FREEMPI(TEMP); 
		FREEMPI(T); 
	} 
	if(m > n){ 
		temp = n + 1; 
		for(j = temp; j <= m; j++){ 
			TEMP1 = ADD0I(P, C); 
			TEMP2 = SUBI(TEMP1, ONE); 
			T = ADD0I(A->A[j], TEMP2); 
			FREEMPI(TEMP1); 
			FREEMPI(TEMP2); 
			TEMP = MOD0(T, P); 
			ADD_TO_MPIA(*DIFF, TEMP, j); 
			FREEMPI(TEMP); 
			TEMP = C; 
			C = INT0(T, P); 
			FREEMPI(TEMP); 
			FREEMPI(T); 
		} 
	} 
	d = 0; 
	k = (int)m; 
	while(k >= 0){ 
		if(EQZEROI((*DIFF)->A[k]) == 0){ 
			d = k; 
			break; 
		}else 
			k--; 
	} 
	if(m != d){ 
		*l = d; 
	} 
	FREEMPI(ONE); 
	FREEMPI(C); 
	return; 
} 
 
/* base(b,n) gives the base b expansion of n > 0: 
 * base[]=baseb[0]+baseb[1]*b+ ...+baseb[i]*b^i. 
 * The integer i is returned, along with  baseb[]. 
 */ 
void BASE_PADIC(MPI *B, MPI *N, MPIA *BASE, USI *j){ 
	MPI *TEMP, *T, *X, *Q; 
	USI i; 
	 
	i = 0; 
	X = COPYI(N); 
	(*BASE) = BUILDMPIA(); 
	while(RSV(X, B) >= 0){ 
		Q = INT0(X, B); 
		TEMP = MULTI(Q, B); 
		T = SUB0I(X, TEMP); 
		FREEMPI(TEMP); 
		TEMP = T; 
		ADD_TO_MPIA(*BASE, TEMP, i); 
		FREEMPI(TEMP); 
		TEMP = X; 
		X = Q; 
		FREEMPI(TEMP); 
		i++; 
	} 
	TEMP = X; 
	ADD_TO_MPIA(*BASE, TEMP, i); 
	FREEMPI(TEMP); 
	*j = i; 
	return; 
} 
 
/* 
 * twoadicsqrt(a,n) n>=3, returns the first n binary digits of a 
 * 2adic sqroot x of a positive integer a=8k+1. Here x=1 or 5 (mod 8). 
 * See http://www.numbertheory.org/courses/MP313/lectures/lecture23/page3.html 
 * and http://www.numbertheory.org/courses/MP313/solns/soln3/page1.html. 
 */ 
void TWOADICSQRT(MPI *A, USI n, MPIA *DIGITS){ 
	MPI *ONE, *TWO, *TEMP; 
	USI i, j, k, l, x, y; 
	MPIA BASE, PROD, DIFF; 
	int z; 
	char buff[20]; 
	FILE *outfile; 
 
	strcpy(buff, "2-adic.out"); 
	outfile = fopen(buff, "w"); 
 
	ONE = ONEI(); 
	*DIGITS = BUILDMPIA(); 
	TEMP = ONEI(); 
	ADD_TO_MPIA(*DIGITS, TEMP, 0); 
	FREEMPI(TEMP); 
	if(n == 1){ 
		printf("1=x[0] is the first digit of the 2-adic square root of "); 
		fprintf(outfile, "1=x[0] is the first digit of the 2-adic square root of "); 
		PRINTI(A); 
		FPRINTI(outfile, A); 
		printf("\n"); 
		fprintf(outfile, "\n"); 
		fflush(stdout); 
		FREEMPI(ONE); 
		printf("where x=x[0]+x[1]2+... is congruent to 1 (mod 4)\n"); 
		fprintf(outfile, "where x=x[0]+x[1]2+... is congruent to 1 (mod 4)\n"); 
		fflush(stdout); 
		fclose(outfile); 
		return; 
	} 
	TEMP = ZEROI(); 
	ADD_TO_MPIA(*DIGITS, TEMP, 1); 
	FREEMPI(TEMP); 
	if(n == 2){ 
		printf("10=x[0]x[1] are the first two digits of the 2-adic square root of "); 
		fprintf(outfile, "10=x[0]x[1] are the first two digits of the 2-adic square root of "); 
		PRINTI(A); 
		FPRINTI(outfile, A); 
		printf("\n"); 
		fprintf(outfile, "\n"); 
		fflush(stdout); 
		printf("where x=x[0]+x[1]2+... is congruent to 1 (mod 4)\n"); 
		fprintf(outfile, "where x=x[0]+x[1]2+... is congruent to 1 (mod 4)\n"); 
		fflush(stdout); 
		FREEMPI(ONE); 
		fclose(outfile); 
		return; 
	} 
	for(k = 2; k < n; k++){ 
		TEMP = ZEROI(); 
		ADD_TO_MPIA(*DIGITS, TEMP, k); 
		FREEMPI(TEMP); 
	} 
	TWO = ADD0I(ONE, ONE); 
	FREEMPI(ONE); 
	BASE_PADIC(TWO, A, &BASE, &x); 
	l = 0; 
	for(k = 3; k <= n; k++){ 
		MULT_PADIC(*DIGITS, *DIGITS, TWO, &PROD, l, l, &y);  
		z = RSV_PADIC(PROD, BASE, y, x); 
		if(z < 0){ 
			SUB_PADIC(BASE, PROD, TWO, &DIFF, x, y, &j);		 
		}else{ 
			SUB_PADIC(PROD, BASE, TWO, &DIFF, y, x, &j);		 
		} 
		FREEMPIA(PROD); 
		if(EQZEROI(DIFF->A[k]) == 0){ 
			TEMP = ONEI(); 
			ADD_TO_MPIA(*DIGITS, TEMP, k - 1); 
			FREEMPI(TEMP); 
			if(k == 3){ 
				l = 2; 
			}else{ 
				l = k - 1; 
			} 
		} 
		FREEMPIA(DIFF); 
	}	 
	FREEMPIA(BASE); 
	for(i = 0; i < n; i++){ 
		PRINTI((*DIGITS)->A[i]); 
		FPRINTI(outfile, (*DIGITS)->A[i]); 
		printf(" "); 
		fprintf(outfile, " "); 
		fflush(stdout); 
	} 
	if(n > 1){ 
		printf("=x[0]...x[%u]\n", n-1); 
		fprintf(outfile, "=x[0]...x[%u]\n", n-1); 
		fflush(stdout); 
	}else{ 
		printf("=x[0]\n"); 
		fprintf(outfile, "=x[0]\n"); 
		fflush(stdout); 
	} 
	if(n > 1){ 
		printf("are the first %u digits of the 2-adic square root x of ", n); 
		fprintf(outfile, "are the first %u digits of the 2-adic square root x of ", n); 
	}else{ 
		printf("is the first digit of the 2-adic square root x of "); 
		fprintf(outfile, "is the first digit of the 2-adic square root x of "); 
	} 
	PRINTI(A); 
	FPRINTI(outfile, A); 
	printf("\n"); 
	fprintf(outfile, "\n"); 
	printf("where x=x[0]+x[1]2+... is congruent to 1 (mod 4)\n"); 
	fprintf(outfile, "where x=x[0]+x[1]2+... is congruent to 1 (mod 4)\n"); 
	fclose(outfile); 
	fflush(stdout); 
	FREEMPI(TWO); 
	return; 
} 
 
MPI *TWOADICSQRTX(MPI *A, MPI *N, MPIA *DIGITS){ 
	USI n; 
	USL t; 
	if(A->S <=0){ 
		printf("A <= 0\n"); 
		return(NULL); 
	} 
	t = MOD0_(A, (USL)8); 
	if(t != 1){ 
		printf("n not of the from 8k+1\n"); 
		return(NULL); 
	} 
	if(N->S <=0){ 
		printf("n <= 0\n"); 
		return(NULL); 
	} 
	if(N->D > 1){ 
		printf("n > 2^16.\n"); 
		return(NULL); 
	} 
	n = (USI)CONVERTI(N);  
	TWOADICSQRT(A, n, DIGITS); 
	return (ONEI()); 
} 
 
/*  
 * PADICSQRT(a,n,p) returns the first n p-adic digits of a 
 * p-adic sqroot x of a positive integer a. Here x=b(mod p), 
 * where b^2=a(mod p) and 0A[k]) == 0){ 
			TEMP = MULT_I(U, 2); 
			TEMP1 = MULT_I(TEMP, sign); 
			FREEMPI(TEMP); 
			TEMP2 = MINUSI(DIFF->A[k]); 
			TEMP = CONGR(TEMP1, TEMP2, P, &PP); 
			FREEMPI(PP); 
			FREEMPI(TEMP1); 
			FREEMPI(TEMP2); 
			ADD_TO_MPIA(*DIGITS, TEMP, k); 
			FREEMPI(TEMP); 
		}else{ 
			TEMP = ZEROI(); 
			ADD_TO_MPIA(*DIGITS, TEMP, k); 
			FREEMPI(TEMP); 
		} 
		l = k; 
		FREEMPIA(DIFF); 
	} 
	FREEMPIA(BASE); 
	for(i = 0; i < n; i++){ 
		if(i){ 
			printf(","); 
			fprintf(outfile, ","); 
			PRINTI((*DIGITS)->A[i]); 
			FPRINTI(outfile, (*DIGITS)->A[i]); 
			fflush(stdout); 
		}else{ 
			PRINTI((*DIGITS)->A[i]); 
			FPRINTI(outfile, (*DIGITS)->A[i]); 
			fflush(stdout); 
		} 
	} 
	temp = n - 1; 
	if(n > 1){ 
		printf("=x[0]...x[%u]\n", n-1); 
		fprintf(outfile, "=x[0]...x[%u]\n", n-1); 
		fflush(stdout); 
	}else{ 
		printf("=x[0]\n"); 
		fprintf(outfile, "=x[0]\n"); 
		fflush(stdout); 
	} 
	if(n > 1){ 
		printf("are the first %u digits of the p-adic square root x of ", n); 
		fprintf(outfile, "are the first %u digits of the p-adic square root x of ", n); 
	}else{ 
		printf("is the first digit of the p-adic square root x of "); 
		fprintf(outfile, "is the first digit of the p-adic square root x of "); 
	} 
	PRINTI(A); 
	FPRINTI(outfile, A); 
	printf("\n"); 
	fprintf(outfile, "\n"); 
	printf("where x=x[0]+x[1]P+... is congruent to "); 
	fprintf(outfile, "where x=x[0]+x[1]P+... is congruent to "); 
	PRINTI(U); 
	FPRINTI(outfile,U); 
        printf(" (mod "); 
        fprintf(outfile, " (mod "); 
	PRINTI(P); 
	FPRINTI(outfile, P); 
	printf(")\n"); 
	fprintf(outfile, ")\n"); 
	fclose(outfile); 
	fflush(stdout); 
	FREEMPI(U); 
	return; 
} 
 
MPI *PADICSQRTX(MPI *A, MPI *N, MPI *P, MPIA *DIGITS){ 
	int t; 
	USI n; 
	MPI *T; 
 
	if(A->S <=0){ 
		printf("A <= 0\n"); 
		return(NULL); 
	} 
	if(N->S <=0){ 
		printf("n <= 0\n"); 
		return(NULL); 
	} 
	if(N->D > 1){ 
		printf("n > 2^16.\n"); 
		return(NULL); 
	} 
	n = (USI)CONVERTI(N);  
 
	if (P->S <= 0 || (P->D == 0 && P->V[0] <= 2)){ 
	  printf("P <= 2\n"); 
	} 
	T = LUCAS(P); 
	t = T->S; 
	FREEMPI(T); 
	if (!t) 
	{ 
	  printf("3rd argument is not a prime\n"); 
	  return NULL; 
	} 
	if (JACOBIB(A, P) != 1) 
	{ 
	  printf("X is not a quadratic residue mod P\n"); 
	  return NULL; 
	} 
	PADICSQRT(A, n, P, DIGITS); 
	return(ONEI()); 
}