// QPI by Han Duong
// ported from QPI 4.3a for the HP48G/GX by Mika Heiskanen & Andre Schoorl
export qpiEXPLN:=100; // max denom for exp(p/q) or ln(p/q)
export qpiMAXINT:=2^20; // largest n allowed for sqrt(n)=a*sqrt(b)
export qpiDIGITS:=10; // controls accuracy (best results at 9 or 10)
qpi_approx();
qpi_asqrtb();
qpi_out();
qpi_outsqrt();
qpi_real();
qpi_complex();
qpi_list();
qpi_root();
qpi_pi();
qpi_ln();
qpi_exp();
//qpi_symb();
EXPORT QPI(r)
BEGIN
case
if TYPE(r)==0 then qpi_real(r); end;
if TYPE(r)==1 then RETURN(r); end;
if TYPE(r)==3 then qpi_complex(r); end;
if TYPE(r)==6 then qpi_list(r); end;
if TYPE(r)==8 then QPI(approx(r)); end;
DEFAULT msgbox("Object type: " + TYPE(r) + " not supported!");
end;
END;
qpi_real(r)
BEGIN
local frac;
if r then
frac:=qpi_approx(r);
if frac(2)<100 then
qpi_out(frac);
else
qpi_root(r,frac);
end;
else
RETURN(0);
end;
END;
qpi_complex(c)
BEGIN
local rpart, ipart;
rpart:=STRING(qpi_real(RE(c)));
ipart:=STRING(qpi_real(abs(IM(c))));
if IM(c)>0 then
expr("'" + rpart + "+" + ipart + "*'");
else
expr("'" + rpart + "-" + ipart + "*'");
end;
END;
qpi_list(l)
BEGIN
local i,n;
n:=SIZE(l);
for i from 1 to n do
l(i):=QPI(l(i));
end;
RETURN(l);
END;
qpi_root(r,frac)
BEGIN
local frac1;
if r^2<500001 then
frac1:=qpi_approx(r^2);
if r<0 then frac1(1):=-frac1(1); end;
frac1(3):=1;
if (frac1(2)<1000) AND (frac1(2)<=frac(2)) then
if frac1(2)<10 then
qpi_out(frac1);
else
qpi_pi(r,frac1);
end;
else // sqrt denom not smaller
qpi_pi(r,frac);
end;
else // r^2>500000
qpi_pi(r,frac);
end; // end_if r^2<500000
END;
qpi_pi(r,frac)
BEGIN
local frac1;
if abs(r/pi)<101 then
frac1:=qpi_approx(r/pi);
frac1(3):=2;
if (frac1(2)<1000) AND (frac1(2)<=frac(2)) then
if frac1(2)<10 then
qpi_out(frac1);
else
qpi_ln(r,frac1);
end;
else // (r/pi) denom not smaller
qpi_ln(r,frac);
end;
else // abs(r/pi)>100
qpi_ln(r,frac);
end; // end_if abs(r/pi)<101
END;
qpi_ln(r,frac)
BEGIN
local frac1,tmp;
tmp:=e^(r);
if tmp<1001 then
// check for LN(0)
if tmp then
frac1:=qpi_approx(tmp);
else
frac1:=qpi_approx(MINREAL);
end;
frac1(3):=3;
if (frac1(1)*frac1(2)==1) OR (frac1(2)>qpiEXPLN) then
qpi_exp(r,frac);
else
if (frac1(2)<=frac(2)) then
if frac1(2)<10 then
qpi_out(frac1);
else
qpi_exp(r,frac1);
end;
else
qpi_exp(r,frac);
end;
end; // end_if p*q==1 or q>50
else // e^(r)>1000
qpi_exp(r,frac);
end; // end_if e^(r)<1001
END;
qpi_exp(r,frac)
BEGIN
local frac1;
if r<0 then
qpi_out(frac);
else
frac1:=qpi_approx(LN(r));
frac1(3):=4;
if frac1(2)>qpiEXPLN then
qpi_out(frac);
else
if frac1(2)<=frac(2) then
qpi_out(frac1);
else
qpi_out(frac);
end;
end;
end;
END;
// returns frac(t+1) where
// frac:={p/q, sqrt(p/q), p/q*pi, ln(p/q), e^(p/q)}
// and list:={p,q,t}
qpi_out(list)
BEGIN
local s0="(", s1=")'";
if list(3)==1 then
qpi_outsqrt(list);
else
if list(1)<0 then s0:="-" + s0; end;
if list(3) then s1:=")" + s1; end;
case
if list(3)==2 then s1:=")*π'"; end;
if list(3)==3 then s0:="LN(" + s0; end;
if list(3)==4 then s0:="e^(" + s0; end;
end;
s0:="'" + s0;
if list(2)==1 then
expr(s0 + abs(list(1)) + s1);
else
expr(s0 + abs(list(1)) + "/" + list(2) + s1);
end;
end;
END;
qpi_outsqrt(list)
BEGIN
local ab1, ab2;
local s0="'";
if list(1)<0 then s0:=s0+"-"; end;
ab1:=qpi_asqrtb(abs(list(1)));
ab2:=qpi_asqrtb(list(2));
if ab1(1)<>ab2(1) then
if ab2(1)==1 then
s0:=s0 + ab1(1) + "*";
else
s0:=s0 + "(" + ab1(1) + "/" + ab2(1) + ")*";
end;
end;
s0:=s0 + "√(";
if ab2(2)==1 then
s0:=s0 + ab1(2);
else
s0:=s0 + ab1(2) + "/" + ab2(2);
end;
expr(s0+")'");
END;
// returns {a,b} where n=a*sqrt(b)
qpi_asqrtb(n)
BEGIN
local div,quo,rem,num,den,nodd;
if n>qpiMAXINT then RETURN({1,n}); end;
div:=1;
num:=n;
den:=4;
nodd:=3;
repeat
quo:=IP(num/den);
rem:=num MOD den;
if rem==0 then
div:=div*(IP(nodd/2)+1);
num:=quo;
else
nodd:=nodd+2;
den:=den+nodd;
end;
until (quo==0) OR (nodd>qpiMAXINT) end;
RETURN({div,num});
END;
// returns {p,q,0} where r=p/q
qpi_approx(r)
BEGIN
local num,inum,den,iden;
local p0,q0,p1,q1,p2,q2;
local quo,rem;
if NOT(r) then RETURN({0,1,0}); end;
num:=abs(r);
inum:=IP(num);
den:=1;
while num-inum do
num:=num*10;
den:=den*10;
inum:=IP(num);
end;
iden:=den;
rem:=den; den:=num;
p1:=0; p2:=1;
q1:=1; q2:=0;
repeat
p0:=p1; p1:=p2;
q0:=q1; q1:=q2;
num:=den; den:=rem;
quo:=IP(num/den);
rem:=num MOD den;
p2:=quo*p1+p0;
q2:=quo*q1+q0;
until 10^qpiDIGITS*abs(inum*q2-iden*p2)<iden*p2 end;
if (r>0) then
RETURN({p2,q2,0});
else
RETURN({−p2,q2,0});
end;
END;
#cas
qpi_symb(f):=
begin
local j,n,g,r;
if (type(f) <> DOM_SYMBOLIC) then return(f); end;
n:=dim(f)+1;
for j from 2 to n do
g:=f[j];
if (type(g) == DOM_FLOAT) then
r:=QPI(g);
f[j]:=r;
end;
if (type(g) == DOM_SYMBOLIC) then
r:=qpif(g);
f[j]:=r;
end;
end;
return(f);
end;
#end