/* bc file squareroot */ /* min(x,y) */ define min(x,y){ if(yy) return(1) if(x==y) return(0) if(x0) return(1) if(a<0) return(-1) return(0) } define abs(n){ if(n>=0) return(n) return(-n) } define mod(a,b){ auto c c=a%b if(a>=0) return(c) if(c==0) return(0) return(c+b) } define mpower(a,b,c){ auto x,y,z x=a y=b z=1 while(y>0){ while(y%2==0){ y=y/2 x=(x*x)%c } y=y-1 z=mod(z*x,c) } return(z) } /* Shanks-Tonelli algorithm. * See "Square roots from 1; 24, 51, 10 to Dan Shanks", * Ezra Brown, The College Mathematics Journal, 30, No. 2, 82-95, 1999 */ define tonelli(a,p){ auto b,e,g,h,i,m,n,q,r,s,t,x,y,z q=p-1 t=mpower(a,q/2,p) if(t==q)return(0)/* a is a quadratic non-residue mod p */ s=q e=0 while(s%2==0){s=s/2;e=e+1} /* p-1=s*2^e */ x=mpower(a,(s+1)/2,p) b=mpower(a,s,p) if(b==1)return(x) for(n=2;n>=2;n++){ t=mpower(n,q/2,p) if(t==q) break } /* n is the least quadratic non-residue mod p */ g=mpower(n,s,p) r=e while(1){ y=b for(m=0;m<=r-1;m++){ if(y==1)break y=(y*y)%p } /*print "(m,x,b,g,r)=(",m,",",x,",",b,",",g,",",r,")\n"*/ /* ord_p(b)=2^m, m <= r-1, so m has decreased */ if(m==0)return(x) z=r-m-1 h=g for(i=0;i0){ "not soluble "; return(-1) } b=gcd1(m,n) y=n/a p=p/a x=mod(b*p,y) return(x) } define gcd1(m,n){ auto a,b,c,h,k,l,q,t if(n==0) return(sign(m)) a=m b=abs(n) c=mod(a,b) if(c==0) return(0) l=1 k=0 while(c>0){ q=(a-c)/b a=b b=c c=mod(a,b) h=l-q*k l=k k=h } return(k) } define gcd2(m,n){ auto a,b,c,h,k,l,q,t if(n==0) return(0) a=m b=abs(n) c=mod(a,b) if(c==0) return(sign(n)) l=0 k=1 while(c>0){ q=(a-c)/b a=b b=c c=mod(a,b) h=l-q*k l=k k=h } q=(a-c)/b if(n<0) return(-k) return(k) } define gcd(m,n){ auto a,b,c a=abs(m) /* a=r[0] */ if(n==0) return(a) b=abs(n) /* b=r[1] */ c=a%b /* c=r[2]=r[0] mod(r[1]) */ while(c>0){ a=b b=c c=a%b /* c=r[j]=r[j-2] mod(r[j-1]) */ } return(b) } /* inv(a,n) returns the inverse of a (mod n), n>0 if gcd(a,n)=1. * uses the fact that |s[j]|1){print "gcd(a,n)>1\n";return(0)} s=gcd1(a,n) if(s<0)return(s+n) return(s) } /* the bth power of a, where a is an integer, b a positive integer.*/ define exp(a,b){ auto x,y,z x=a y=b z=1 while(y>0){ while(y%2==0){ y=y/2 x=x*x } y=y-1 z=z*x } return(z) } pglobal[0]=2 pglobal[1]=3 pglobal[2]=5 pglobal[3]=7 pglobal[4]=11 pglobal[5]=13 pglobal[6]=17 pglobal[7]=19 pglobal[8]=23 pglobal[9]=29 pglobal[10]=31 pglobal[11]=37 pglobal[12]=41 pglobal[13]=43 pglobal[14]=47 pglobal[15]=53 pglobal[16]=59 pglobal[17]=61 pglobal[18]=67 pglobal[19]=71 pglobal[20]=73 pglobal[21]=79 pglobal[22]=83 pglobal[23]=89 pglobal[24]=97 pglobal[25]=101 pglobal[26]=103 pglobal[27]=107 pglobal[28]=109 pglobal[29]=113 pglobal[30]=127 pglobal[31]=131 pglobal[32]=137 pglobal[33]=139 pglobal[34]=149 pglobal[35]=151 pglobal[36]=157 pglobal[37]=163 pglobal[38]=167 pglobal[39]=173 pglobal[40]=179 pglobal[41]=181 pglobal[42]=191 pglobal[43]=193 pglobal[44]=197 pglobal[45]=199 pglobal[46]=211 pglobal[47]=223 pglobal[48]=227 pglobal[49]=229 pglobal[50]=233 pglobal[51]=239 pglobal[52]=241 pglobal[53]=251 pglobal[54]=257 pglobal[55]=263 pglobal[56]=269 pglobal[57]=271 pglobal[58]=277 pglobal[59]=281 pglobal[60]=283 pglobal[61]=293 pglobal[62]=307 pglobal[63]=311 pglobal[64]=313 pglobal[65]=317 pglobal[66]=331 pglobal[67]=337 pglobal[68]=347 pglobal[69]=349 pglobal[70]=353 pglobal[71]=359 pglobal[72]=367 pglobal[73]=373 pglobal[74]=379 pglobal[75]=383 pglobal[76]=389 pglobal[77]=397 pglobal[78]=401 pglobal[79]=409 pglobal[80]=419 pglobal[81]=421 pglobal[82]=431 pglobal[83]=433 pglobal[84]=439 pglobal[85]=443 pglobal[86]=449 pglobal[87]=457 pglobal[88]=461 pglobal[89]=463 pglobal[90]=467 pglobal[91]=479 pglobal[92]=487 pglobal[93]=491 pglobal[94]=499 pglobal[95]=503 pglobal[96]=509 pglobal[97]=521 pglobal[98]=523 pglobal[99]=541 pglobal[100]=547 pglobal[101]=557 pglobal[102]=563 pglobal[103]=569 pglobal[104]=571 pglobal[105]=577 pglobal[106]=587 pglobal[107]=593 pglobal[108]=599 pglobal[109]=601 pglobal[110]=607 pglobal[111]=613 pglobal[112]=617 pglobal[113]=619 pglobal[114]=631 pglobal[115]=641 pglobal[116]=643 pglobal[117]=647 pglobal[118]=653 pglobal[119]=659 pglobal[120]=661 pglobal[121]=673 pglobal[122]=677 pglobal[123]=683 pglobal[124]=691 pglobal[125]=701 pglobal[126]=709 pglobal[127]=719 pglobal[128]=727 pglobal[129]=733 pglobal[130]=739 pglobal[131]=743 pglobal[132]=751 pglobal[133]=757 pglobal[134]=761 pglobal[135]=769 pglobal[136]=773 pglobal[137]=787 pglobal[138]=797 pglobal[139]=809 pglobal[140]=811 pglobal[141]=821 pglobal[142]=823 pglobal[143]=827 pglobal[144]=829 pglobal[145]=839 pglobal[146]=853 pglobal[147]=857 pglobal[148]=859 pglobal[149]=863 pglobal[150]=877 pglobal[151]=881 pglobal[152]=883 pglobal[153]=887 pglobal[154]=907 pglobal[155]=911 pglobal[156]=919 pglobal[157]=929 pglobal[158]=937 pglobal[159]=941 pglobal[160]=947 pglobal[161]=953 pglobal[162]=967 pglobal[163]=971 pglobal[164]=977 pglobal[165]=983 pglobal[166]=991 pglobal[167]=997 /* * the Brent-Pollard method for returning a proper factor of a composite n. * See R. Brent, Bit 20, 176-184 */ define brent(n){ auto a,y,r,g,x,i,k,f "BRENT-POLLARD: SEARCHING FOR A PROPER FACTOR OF ";n a=1;y=0;r=1;g=1;prod=1 while(g==1){ x=y for(i=1;i<=r;i++)y=(y*y+a)%n k=0 f=0 while(f==0){ y=(y*y+a)%n k=k+1 z=abs(x-y) prod=prod*z if(k%10==0){ g=gcd(prod,n) prod=1 if (g>1)f=1 } if(k>=r)f=1 } r=2*r;print "r=",r,"\n" if(g==n || r == 16384){ g=1 r=1 y=0 a=a+1 print "increasing a\n" if(a==3){ print "Brent-Pollard failed to find a factor\n" return(0) } } } print g," is a proper factor of ",n,"\n" return(g) } define pollard(n){ auto i,p,t,b b=t=2 p=1 for(i=2;i<=10^4;i++){ if(i%10==0){"i=";i} t=mpower(t,i,n)/* now t=b ^(i!) */ p=gcd(n,t-1) if(p>1){ if(p 1 and odd, gcd(n,b)=1, or more generally, n does not divide b. * If miller(n,b)=1, then n passes Miller's test for base b and n is * either a prime or a strong pseudoprime to base b. * if miller(n,b)=0, then n is composite. */ define miller(n,b){ auto a,s s=(n-1)/2 a=s while(a%2==0)a=a/2 b=mpower(b,a,n) if(b==1)return(1) while(a<=s){ if(b==n-1)return(1) b=mod(b*b,n) a=2*a } return(0) } /* * n > 1 is distinct from pglobal[0],...,pglobal[4]. * if q(n)=1, then n passes Miller's test for bases pglobal[0],...,pglobal[4] * and is likely to be prime. * if q(n)=0, then n is composite. */ define q(n){ auto i for(i=0;i<=4;i++){ if(miller(n,pglobal[i])==0){ return(0) } } return(1) } /* * n>1 is not divisible by pglobal[0],...,pglobal[167]. * v(n) returns a factor of n which is < 1,000,000 (and hence prime) * or which passes Miller's test for bases pglobal[0],...,pglobal[4] and is * therefore likely to be prime. */ define v(n){ auto f,x,y,b b=1000 if(n 1,000,000, passes Miller's test * and is not divisible by pglobal[0],...,pglobal[167]. It is likely to be * prime. * primefactors(n) returns the number lglobal-t of q-prime factors of n. * rglobal[] and lglobal are global variables. * The prime and q-prime factors of n are qglobal[i],...,qglobal[jglobal-1] * with exponents * kglobal[i],...,kglobal[jglobal-1] where i is the value of the global * variable jglobal before primefactors(n) is called. */ define primefactors(n){ auto b,p,x,k,t b=1000 x=babydivide(n) t=lglobal while(x!=1){ k=0 p=v(x) while(x%p==0){ k=k+1 x=x/p } if(p>b*b){ rglobal[lglobal]=p lglobal=lglobal+1 } qglobal[jglobal]=p kglobal[jglobal]=k jglobal=jglobal+1 } return(lglobal-t) } /* * Selfridge's test for primality - see "Prime Numbers and Computer * Methods for Factorization" by H. Riesel, Theorem 4.4, p.106. * input: n (q-prime) * first finds the prime and q-prime factors of n-1. If no q-prime factor * is present and 1 is returned, then n is prime. However if at least one * q-prime is present and 1 is returned, then n retains "q-prime" status. * If 0 is returned, then either n or one of the q-prime factors of n-1 is * composite. */ define selfridge(n){ auto i,x,s,t,u i=jglobal u=primefactors(n-1) cglobal=u+cglobal /* cglobal,jglobal,lglobal are global variables. */ /* primefactors(n-1) returns jglobal-i primes and q-primes qglobal[i],...,qglobal[jglobal-1] */ /* and q-primes rglobal[l-u],...,rglobal[lglobal-1], where u>=0. */ while(i<=jglobal-1){ for(x=2;x0){ t=selfridge(rglobal[i]) if(t==0){ return(0) } i=i+1 cglobal=cglobal-1 } return(s) } /* the Chinese remainder theorem for the congruences x=a(mod m) * and x=b(mod n), m>0, n>0, a and b arbitrary integers. * The construction of O. Ore, American Mathematical Monthly, * vol.59,pp.365-370,1952, is implemented. * Same as chinese() in gcd, but with printing suppressed, except that -1 * is returned if there is no solution. */ define chinese(a,b,m,n) { auto c,d,x,y,z d = gcd(m,n) if(mod(a-b,d)!=0){ return(-1) } x= m/d;y=n/d z=(m*n)/d c = mod(b*gcd1(x,y)*x + a*gcd2(x,y)*y,z) return(c) } define chinesea(a[],m[],n){ auto i,mm,x mm=m[0] x=a[0] for(i=1;i2, two solutions mod 2^(n-1):number=2,modulus=2^(n-1) * If p>2, two solutions mod p^n: number=2,modulus=p^n * 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)): number=1, modulus=p^(m+1) * In case (b), the solution is x=0 (mod p^m): number=1, modulus=p^m * In case (ii) gcd(a,p^n)=p^r, r2 and A=1 (mod 8). * number=2, modulus=2^(n-m-1) */ define sqroot3(a,p,n){ auto aa,d,m,r,s,t,u,v d=a%p if(d){ if(p==2){ t=sqroot2(a,n) if(n==1 || n==2){ number=1 exponent=2 }else{ number=2 exponent=2^(n-1) } return(t) }else t=sqroot1(a,p,n) exponent=p^n number=2 return(t) }else{ u=p^n v=a%u if(v==0){ number=1 if(n%2==0){ exponent=p^(n/2) }else{ exponent=p^(1+n/2) } return(0) } r=0 aa=a v=aa%p while(v==0 && r<=n){ aa=aa/p v=aa%p r=r+1 } if(r%2){ return(-1) }else{ m=r/2 s=n-r if(p==2){ t=sqroot2(aa,s) if(s==1 || s==2){ exponent=2^(m+1) number=1 }else{ number=2 exponent=2^(n-m-1) } if(t==-1){ return(-1) }else{ return((2^m)*t) } }else{ t=sqroot1(aa,p,s) exponent=p^(n-m) number=2 if(t==-1){ return(-1) }else return((p^m)*t) } } } } define solution(){ auto i,j,x for(i=0; i1, we use the Chinese remainder theorem after solving mod * qglobal[i]^kglobal[i], i=0,...,e-1=omega(n)-1. * The array solution[0],...,solution[numbr-1] consists of the solutions * (mod n) in the range 0<=x<=n/2 and is used in cornacchia(). * numbr is a global variable. */ define sqroot(d,n,flag){ auto e,i,j,k,t,z globalsqcount=0 reduced_modulus=1 if(n==1){ reduced_solution[0]=0 numbr=1 solution[0]=0 if(flag){ print "Solution of x^2=",d,"(mod ",n,") is x=0 (mod 1)\n" print "The number of solutions (mod ",n,") is " } return(1) } numprimefactors=omega(n) for(i=0;ireduced_modulus){ reduced_solution[0]=reduced_modulus-soln[0] reduced_solution[1]=-reduced_solution[0] globalsqcount=2 } if(2*soln[0]=y. * Here a>0,b>0,m>a+b, gcd(a,b)=1=gcd(a,m). * If a=b=1, we get only solutions with 0m){ print "a+b>m\n" halt } temp=gcd(a,m) if(temp>1){ print "gcd(a,m)>1\n" halt } temp=gcd(a,b) if(temp>1){ print "gcd(a,b)>1\n" halt } a1=inv(a,m) a2=a1*(-b) ma=m/a mb=m/b n=sqroot(a2,m,0) print "Solving " if(a>1){ print a } print"x^2+" if(b>1){ print b } print "y^2=",m,":\n" if(n==0){ print "Number of primitive solutions=" return(0) } soln_number=0 for(i=0;i1){ r=mod(aa,bb) q1=aa/bb aa=bb bb=r qq= -q1 t2=tt+(qq*t1) tee2=rsv(t2*t2,mb) tt=t1 t1=t2 } } } if(a==1 && b==1){ print "Number of positive primitive solutions with y<=x is " }else{ print "Number of positive primitive solutions is " } return(soln_number) } /* Solving ax^2+bx+c=0 (mod n), where gcd(a,n)=1. * k=oldquadratic(a,b,c,n,flag) returns number k of solutions. * If k>0, we get a global array: * quadratic_solution[0],...,quadratic_solution[k-1]. * First solve t^2=b^2-4ac (mod 4n), -n0 && solution[i] 0.*/ /* case 1: b even */ define qbeven(a,b,c,n,print_flag){ auto d,i,j,k,s,temp[],an,count,dover4 d=b^2-4*a*c dover4=d/4 an=a*n if(print_flag){ print "solving X^2 equiv ",dover4, " (mod ",an,")\n" } s=sqroot(dover4,an,0) if(s==0){ if(print_flag){ print "no solution\n" } return(0) } /* now we have x=solution[0],...,solution[numbr-1], 0<=x<=an/2 */ count=0 for(i=0;i0 && 4*solution[i] != an){ temp[i+numbr]=-solution[i] count=count+1 } } /* We now have count solutions in the range -an/2 < temp[i] <= an/2 */ k=0 for(j=0;j0 && 2*solution[i] != fouran){ temp[i+numbr]=-solution[i] count=count+1 } } /* We now have count solutions in the range -2an < temp[i] <= 2an */ k=0 for(j=0;j