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;