📄 p-adic.c
字号:
#define _CRT_SECURE_NO_DEPRECATE
#include "integer.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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 0<b<p.
* See http://www.numbertheory.org/courses/MP313/lectures/lecture23/page3.html
* and http://www.numbertheory.org/courses/MP313/solns/soln3/page3.html.
*/
void PADICSQRT(MPI *A, USI n, MPI *P, MPIA *DIGITS){
MPI *U, *PP, *TEMP, *TEMP1, *TEMP2;
MPIA BASE, PROD, DIFF;
USI i, j, temp, x, l, y, k;
int z;
long int sign;
char buff[20];
FILE *outfile;
strcpy(buff, "p-adic.out");
outfile = fopen(buff, "w");
U = SQRTM(A, P);
BASE_PADIC(P, A, &BASE, &x);
sign = 1;
l = 0;
TEMP = COPYI(U);
*DIGITS = BUILDMPIA();
ADD_TO_MPIA(*DIGITS, TEMP, 0);
FREEMPI(TEMP);
for(k = 1;k <= n;k++){
MULT_PADIC(*DIGITS, *DIGITS, P, &PROD, l, l, &y);
z = RSV_PADIC(PROD, BASE, y, x);
if(z < 0){
SUB_PADIC(BASE, PROD, P, &DIFF, x, y, &j);
sign = -1;
}else{
SUB_PADIC(PROD, BASE, P, &DIFF, y, x, &j);
}
FREEMPIA(PROD);
if(EQZEROI(DIFF->A[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());
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -