math_ext.sa


Generated by gen_html_sa_files from ICSI. Contact gomes@icsi.berkeley.edu for details
 


class INT_EXT

class INT_EXT is is_prime(x:INT):BOOL is -- Is __x__ prime? if x.is_even then if x=2.int then return true; else return false; end; elsif 3.int.evenly_divides(x) then if x=3.int then return true; else return false; end; elsif 5.int.evenly_divides(x) then if x=5.int then return true; else return false; end; elsif 7.int.evenly_divides(x) then if x=7.int then return true;else return false; end; elsif 11.int.evenly_divides(x) then if x=11.int then return true; else return false; end; elsif 13.int.evenly_divides(x) then if x=13.int then return true;else return false; end; elsif x<13.int then return false; end; d:INT:=x.sqrt; -- r1:=5; r2:=7; -- \pm 1 (mod 6) r1:INT:=17.int; r2:INT:=19.int; loop while!(r1<=d); if r1.evenly_divides(x) then return false; elsif r2.evenly_divides(x) then return false; end; r1:=r1+6.int; r2:=r2+6.int; end; return true; end; extended_gcd(i,j:INT, out f1: INT, out f2:INT):INT is -- gcd = i*f1 + j*f2 -- x:SAME:=one; y:SAME:=zero; u:SAME:=zero; v:SAME:=one; a,b,q:INT; x:INT:=#(1); y:INT:=#(0); u:INT:=#(0); v:INT:=#(1); if i.is_neg then x:=-x; a:=-i; else a:=i; end; if j.is_neg then y:=-y; b:=-j; else b:=j; end; loop if b.is_zero then f1:=x; f2:=y; return a; end; -- a.divmod(b,out q, out a); q:=a/b; a:=a-q*b; x:=x-q*u; y:=y-q*v; if a.is_zero then f1:=u; f2:=v; return b; end; -- b.divmod(a,out q, out b); q:=b/a; b:=b-q*a; u:=u-q*x; v:=v-q*y; end; end; inv(p,g:INT):INT is -- inverse of g as finite field Zp. -- i.e. p:prime. g*inv(p,g)=1 (mod p). f1,f2:INT; g:=g%p; -- make "g>0" gcd::=extended_gcd(g, p, out f1, out f2); return f1; end; power_mod(n,j,p:INT):INT pre j.is_non_neg and p.is_pos is -- Returns (n^j) % p. (j>=0 and p>0) x :INTI:= #(n); z :INTI:= #(1); pl:INTI:=#(p); i ::= j; loop while!(i.is_pos); -- z * x^i = self ^ i0 if i.is_odd then z := (z*x)%pl end; x := (x*x)%pl; i := i/2 end; return z.int end; end;

class INTI_EXT

class INTI_EXT is --------------------- primes ------------------- is_spsp(x,a:INTI):BOOL is -- is prime or strong pseudo prime of base "a"? s:INTI:=0.inti; d:INTI:=x-1.inti; loop while!(d.is_even); s:=s+1.inti; d:=d/2.inti; end; ad:INTI:=1.inti; -- ad=(a**d)%x loop while!(d.is_pos); if d.is_odd then ad:=(ad*a)%x; end; d:=d/2.inti; a:=(a*a)%x; end; if ad=1.inti then return true; end; loop r::=0.inti.upto!(s-1.inti); if ad=(x-1.inti) then return true; end; ad:=(ad*ad)%x; -- ad=a**(d*2**r) end; return false; end; is_fpsp(x,a:INTI):BOOL is -- is prime or Fermat's pseudo prime of base "a"? -- return (a^(x-1.inti)%x=1.inti); d:INTI:=x-1.inti; ad:INTI:=1.inti; an:INTI:=a; loop while!(d.is_pos); if d.is_odd then ad:=(ad*an)%x; end; d:=d/2.inti; an:=(an*an)%x; end; return ad=1.inti; end; is_prime(x:INTI):BOOL is -- Is __x__ prime? if x.is_even then if x=2.inti then return true; else return false; end; elsif 3.inti.evenly_divides(x) then if x=3.inti then return true; else return false; end; elsif 5.inti.evenly_divides(x) then if x=5.inti then return true; else return false; end; elsif 7.inti.evenly_divides(x) then if x=7.inti then return true;else return false; end; elsif 11.inti.evenly_divides(x) then if x=11.inti then return true; else return false; end; elsif 13.inti.evenly_divides(x) then if x=13.inti then return true;else return false; end; elsif x<2.inti then return false; end; -- Check if spsp or fpsp. if (x>1000000000.inti)and(~is_fpsp(x,13.inti)) then return false; end; d:INTI:=x.sqrt; -- r1:=5; r2:=7; -- \pm 1 (mod 6) -- r1:=11; r2:=13; r1:INTI:=17.inti; r2:INTI:=19.inti; loop while!(r1<=d); if r1.evenly_divides(x) then return false; elsif r2.evenly_divides(x) then return false; end; r1:=r1+6.inti; r2:=r2+6.inti; end; return true; end; next_prime(n:INTI):INTI is -- prime next to n. (minimum prime >n) if n<2.inti then return 2.inti; end; k::=n+1.inti; if k.is_even then k:=k+1.inti; end; loop until!(is_prime(k)); k:=k+2.inti; end; return k; end; ------------ multi GCD --------------- gcd(i,j:INTI):INTI is a:INTI:=i.abs; b:INTI:=j.abs; -- x:SAME:=one; y:SAME:=zero; u:SAME:=zero; v:SAME:=one; x:INTI:=#(1); y:INTI:=#(0); u:INTI:=#(0); v:INTI:=#(1); loop if b.is_zero then return a; end; -- a.divmod(b,out q, out a); a:=a%b; if a.is_zero then return b; end; -- b.divmod(a,out q, out b); b:=b%a; end; end; gcd(a:ARRAY{INTI}):INTI is -- multi GCD. return GCD of elements of a[]. g:INTI:=0.inti; loop g:=gcd(a.elt!, g); end; return g; end; extended_gcd(i,j:INTI, out f1: INTI, out f2:INTI):INTI is -- gcd = i*f1 + j*f2 -- x:SAME:=one; y:SAME:=zero; u:SAME:=zero; v:SAME:=one; a,b,q:INTI; x:INTI:=#(1); y:INTI:=#(0); u:INTI:=#(0); v:INTI:=#(1); if i.is_neg then x:=-x; a:=-i; else a:=i; end; if j.is_neg then y:=-y; b:=-j; else b:=j; end; loop if b.is_zero then f1:=x; f2:=y; return a; end; -- a.divmod(b,out q, out a); q:=a/b; a:=a-q*b; x:=x-q*u; y:=y-q*v; if a.is_zero then f1:=u; f2:=v; return b; end; -- b.divmod(a,out q, out b); q:=b/a; b:=b-q*a; u:=u-q*x; v:=v-q*y; end; end; extended_gcd(a:ARRAY{INTI}, out factor:ARRAY{INTI}):INTI is -- multi GCD. return GCD g. g = a . factor factor:=#(a.size); f1,f2:INTI; g:INTI:=0.inti; loop i::=a.ind!; g:=extended_gcd(a[i],g,out f1,out f2); if i.is_pos then loop j::=0.upto!(i-1); factor[j]:=factor[j]*f2; end; end; factor[i]:=f1; end; return g; end; inv(p,g:INTI):INTI is -- inverse of g as finite field Zp. -- i.e. p:prime. g*inv(p,g)=1 (mod p). f1,f2:INTI; g:=g%p; -- make "g>0" gcd::=extended_gcd(g, p, out f1, out f2); return f1; end; factorize(n:INTI):ARRAY{INTI} is -- return array of factors with duplication n:=n.abs; f:ARRAY{INTI}:=#; r1::=2.inti; loop while!((n%r1).is_zero); f:=f.append(|r1|); n:=n/r1; end; r1:=3.inti; loop while!((n%r1).is_zero); f:=f.append(|r1|); n:=n/r1; end; r1:=5.inti; r2::=7.inti; --r=\pm 1 (mod 6). So, step s is \pm 2(mod 6). d::=n.sqrt; loop while!(r1<=d); if (n%r1).is_zero then loop while!((n%r1).is_zero); f:=f.append(|r1|); n:=n/r1; end; d:=n.sqrt; end; if (n%r2).is_zero then loop while!((n%r2).is_zero); f:=f.append(|r2|); n:=n/r2; end; d:=n.sqrt; end; r1:=r1+6.inti; r2:=r2+6.inti; end; if (n /= 1.inti)or(f.size.is_zero.not) then f:=f.append(|n|); end; return f; end; private getDivisorsS(i:CARD, divisor:INTI,factors:ARRAY{INTI}, factord:ARRAY{CARD}):ARRAY{INTI} is if i>=factors.size then return |divisor|; end; divisors:ARRAY{INTI}:=#; loop j::=0.upto!(factord[i]); divisors:=divisors.append(getDivisorsS(i+1,divisor,factors,factord)); divisor:=divisor*factors[i]; end; return divisors; end; getDivisors(n:INTI):ARRAY{INTI} is -- get all divisors of n factors:ARRAY{INTI}:=factorize(n); factord:ARRAY{CARD}:=|1|; i:CARD:=0; loop while!(i<factors.size); if factors[i]=factors[i+1] then factord[i]:=factord[i]+1; factors:=ARRAY_EXT{INTI}::delete_at(i+1,factors); else i:=i+1; factord[i]:=1; end; end; return getDivisorsS(0,1.inti,factors,factord); end; checkDivZ(a0,b0,p:INTI):BOOL is -- true if exist "k" s.t. (b+k*prime)|a in Z a::=a0.abs; b::=b0.abs%p; if b.is_zero then return (a%p).is_zero; end; loop while!( (a%p).is_zero); a:=a/p; end; -- x=b or x=-b mod p <=> (x-b)(x+b)=0 mod p <=> x^2=b^2 mod p b2::=(b*b)%p; if a<2500.inti then if ((a*a)%p)=b2 then return true; end; -- (b+k*prime)=-a/2 then k=(-a/2-b)/p, -- (b+k*prime)=a/2 then k=(a/2-b)/p loop k:INTI:=((-a/2.inti-b)/p).upto!((a/2.inti-b)/p); if (a%(b+k*p)).is_zero then return true; end; end; return false; elsif a<1000000.inti then sqrt_i::=a.sqrt; d::=1.inti+(a%2.inti); i:INTI:=1.inti; loop while!(i<=sqrt_i); if (a%i).is_zero then if (i*i)%p=b2 then return true; end; ai::=a/i; if (ai*ai)%p=b2 then return true; end; end; i:=i+d; end; else dv::=getDivisors(a); loop i::=0.upto!(dv.size-1); d::=dv[i]; if (d*d)%p = b2 then return true; end; end; end; return false; end; end;

class RAT_EXT

class RAT_EXT is continued_fraction(r:RAT):ARRAY{INTI} is -- r = a0+1/(a1+1/(... a:ARRAY{INTI}:=#; loop q:INTI:=r.num/r.denom; a:=a.append(|q|); r:=r-#RAT(q); if r.is_zero then break!; end; r:=#RAT(r.denom, r.num); end; return a; end; end;

class VEC_ALG

class VEC_ALG is atn2(x,y:FLT):FLT is -- similar to atan2. return 0<=atn2<4 while 0<=arg(x,y)<2pi s:FLT; if (x=0.0)and(y=0.0) then return 0.0; end; s:=y.abs/(x.abs+y.abs); if (y>=0.0) then if x>=0.0 then return s; else return 2.0-s; end; else if x>=0.0 then return 4.0-s; else return 2.0+s; end; end; end; rotation(x0, y0, x1, y1, x2, y2:INT):INT is -- rotational order of 3-vector p0, p1, p2. -- rotation of 3-pts. p0, p1, p2 = -1,0,1. -- 1: p0-p1-p2 run anti-clockwise. -- -1: p0-p1-p2 run clockwise. -- 0: singular case. r,px0,py0:INT; t0,t1,t2:FLT; if (x0.is_zero)and(y0.is_zero) then return 0.int; end; if (x1.is_zero)and(y1.is_zero) then return 0.int; end; if (x2.is_zero)and(y2.is_zero) then return 0.int; end; --px0:=INT(x0); py0:=INT(y0); --r:=(INT(x1)-px0)*(INT(y2)-py0)-(INT(y1)-py0)*(INT(x2)-px0); --if r>0 then return 1; elsif r<0 then return -1; else return 0; end; t0:=atn2(x0.flt,y0.flt); t1:=atn2(x1.flt,y1.flt); if t1<t0 then t1:=t1+4.0; end; t2:=atn2(x2.flt,y2.flt); if t2<t0 then t2:=t2+4.0; end; if (t0=t1)or(t0=t2)or(t1=t2) then return 0.int; elsif t1<t2 then return -1; else return 1.int; end; end; sLength(inout x, inout y:INT, d:INT) is -- change length of the vector(x,y) to d. I assume length(x,y)/=0 vx::=x; vy::=y; l::=vx*vx+vy*vy; if l.is_non_zero then l:=l.flt.sqrt.round.int; x:=(vx*d)/l; y:=(vy*d)/l; end; end; end;

class TEST_INTI_EXT

class TEST_INTI_EXT is test_inti(p:INT) is #OUT+"test: 10^"+p.str+"\n"; n0:INTI:=(10.inti)^p; n1:INTI:=n0+100.inti; count:INT; t:FLTD; -- count:=0; DATE::mark_time; loop n:INTI:=n0.upto!(n1); if INTI_EXT::is_prime0(n) then count:=count+1; end; end; t:=DATE::diff_time; #OUT+"count="+count.str+" time="+t.str+"\n"; -- count:=0; DATE::mark_time; loop n:INTI:=n0.upto!(n1); if INTI_EXT::is_prime1(n) then count:=count+1; end; end; t:=DATE::diff_time; #OUT+"count="+count.str+" time="+t.str+"\n"; -- return; end; main is test_inti(4); test_inti(5); test_inti(6); test_inti(7); test_inti(8); test_inti(9); test_inti(10); test_inti(11); test_inti(12); test_inti(13); end; end;