How to use in Home or CAS:
QPI(number)
Returns a decimal in the form of p/q, (p/q)*pi, sqrt(p/q), e^(p/q), or ln(p/q). The form is based on the size of the denominator q -- the program tries to use the smallest q.
Please note that you MUST make two changes in this source. Within the subroutine qpi_out() you must make sure that the line
if list(3)==2 then s1:=")*π'"; end;
shows the pi symbol after the multiplication symbol. Chances are this forum does not properly handle the unicode. Again, it MUST be the pi symbol and not the word 'pi'.
Also make sure the line
s0:="√("; s1:=")'";
has the sqrt symbol before the ( in s0.
Lastly, you may change qpiEXPLN to whatever cutoff denominator you wish. The default is 50 (minus 1) so as to match the behavior of the original QPI program from the HP48 series.
BEGIN CODE
qpi_approx();
qpi_out();
qpi_real();
qpi_root();
qpi_pi();
qpi_ln();
qpi_exp();export qpiEXPLN:=500; // max denom - 1
EXPORT QPI(r)
BEGIN
if r then
qpi_real(r);
else
RETURN(0);
end;
END;qpi_real(r)
BEGIN
local frac;
frac:=qpi_approx(r);if frac(2)<100 then
qpi_out(frac);
else
qpi_root(r,frac);
end;
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);
elsefrac1:=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;qpi_out(list)
BEGIN
local s0="(", s1=")'";if list(3)==1 then
s0:="√("; s1:=")'"; // <-- change √ to sqrt symbol
if list(1)<0 then
s0:="'-" + s0;
else
s0:="'" + s0;
end;else
if list(1)<0 then s0:="-" + s0; end;
if list(3) then s1:=")" + s1; end;
if list(3)==2 then s1:=")*π'"; end; // <-- change π to pi symbolcase
if list(3)==3 then s0:="LN(" + s0; end;
if list(3)==4 then s0:="e^(" + s0; end;
end;s0:="'" + s0;
end;
if list(2)==1 then
expr(s0 + abs(list(1)) + s1);
else
expr(s0 + abs(list(1)) + "/" + list(2) + s1);
end;END;
qpi_approx(r)
BEGIN
local num,inum,den,iden;
local p0,q0,p1,q1,p2,q2;
local quo,rem,digs=9;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^digs*abs(inum*q2-iden*p2)<iden*p2 end;if (r>0) then
RETURN({p2,q2,0});
else
RETURN({-p2,q2,0});
end;END;
Edited: 9 Nov 2013, 10:46 p.m. after one or more responses were posted