Chris Angelico wrote:
Wow, someone else who knows REXX and OS/2! REXX was the first bignum language I met, and it was really cool after working in BASIC and 80x86 assembly to suddenly be able to work with arbitrary-precision numbers!
Yes, my "big num" research stuff was initially done in REXX, on VM/CMS. I later ported my libraries over to OS/2 and continued with that well into the '90s, when I discovered Unix and 'bc'. Many folks are not aware that 'bc' also has arbitrary precision floating point math and a standard math library. It is much faster than REXX because the libraries are written in C, and unlike REXX they do not have to be implemented in the interpreter. The syntax of 'bc' is C-like, which is its only down-side for new students who have never had any language training. REXX was a great business language, particularly when CMS Pipelines was introduced.
Just for fun, and a trip down memory lane, you can take a look at some of my ancient REXX code... this code is a REXX math library designed to be used from the command line, written in REXX. The primary scientific functions were implemented, as well as some code to calculate PI... most of the algorithms can be ported to 'bc' easily, but the 'bc' algorithms will run much faster, of course.
Back in the day, REXX was the 'new BASIC' ... now I use Python.
/********************************************************************/ /********************************************************************/ /** COMPUTE COMMAND LINE SCIENTIFIC CALCULATOR **/ /********************************************************************/ /********************************************************************/ /** **/ /** IBM Corporation **/ /** HARRISMH at RCHVMP2 **/ /** EL8/663-1 B627 **/ /** Rochester, MN 55901 **/ /** **/ /** AUTHOR: Marcus Harris **/ /** DATE: 93/10/22 ( port from VM/CMS ) **/ /** UPDATE: 98/03/07 **/ /** VER: 2.0a **/ /** **/ /********************************************************************/ /********************************************************************/ /** syntax **/ /** **/ /** COMPUTE expression<;expression><;expression><@digits> **/ /** **/ /** **/ /** The expression(s) will be computed and displayed in terminal **/ /** line mode to arbitrary <@digits> of accuracy. **/ /** **/ /** The expression(s) may be any REXX math clause and may include **/ /** a variable assignment, for use in a subsequent expression: **/ /** ie., COMPUTE A=3;B=7;A/B;A*B@30 **/ /** (will compute both the quotient and product of A & B) **/ /** **/ /********************************************************************/ /********************************************************************/ /** NOTES **/ /** **/ /** COMPUTE expression<;expression><;expression><@digits> **/ /** **/ /** This program exploits Rexx INTERPRET and NUMERIC DIGITS **/ /** **/ /** This exec is portable to OS/2, NT and w95 Rexx/objectRexx **/ /** without changes. **/ /** **/ /********************************************************************/ /********************************************************************/ /** updates **/ /** 93/10/21 mhh New Program (port from VM/CMS) **/ /** 98/03/07 mhh New Version 2.0a **/ /** This version includes trigonometric, logarithmic, **/ /** exponential and combinatorial functions. **/ /** **/ /** See the REXROOTS ABOUT file for a discussion **/ /** of the included functions and some examples, **/ /** using the COMPUTE program. **/ /** **/ /********************************************************************/ /********************************************************************/ /** dependencies **/ /** **/ /** Numeric Fuzz: **/ /** Most of these routines bump-up the numeric digits **/ /** by a fuzzFactor. Rexx fuzz is used to terminate **/ /** the do-forever iteration at the correct number of **/ /** required places. **/ /** The routine then sets the numeric digits back to **/ /** the application setting and returns result-0. **/ /** The (result-0) forces truncation/rounding to give **/ /** the expected result. **/ /** Some implementations of REXX do not support the **/ /** fuzz option; the iterative do-forever methods **/ /** would need modification for correct termination. **/ /** **/ /********************************************************************/ /********************************************************************/ /** mainline **/ /********************************************************************/ arg expression '@' max_digits . select when expression='' | expression='?' then say syntax_diagram() when datatype(max_digits,'W') & max_digits>0 then, numeric digits max_digits otherwise numeric digits 18 end call evaluate expression exit 0 /********************************************************************/ /** procedures **/ /********************************************************************/ SYNTAX_DIAGRAM: procedure return'Syntax: COMPUTE expression <;expression><@precision>' EVALUATE: procedure expose max_digits arg expression signal on error; signal on syntax /* 502 digits pi/2 */ hpi="1.57079632679489661923132169163975144209858469968755291048747229615390820314310449931401741267105853" hpi=hpi"3991074043256641153323546922304775291115862679704064240558725142051350969260552779822311474477465190" hpi=hpi"9822144054878329667230642378241168933915826356009545728242834617301743052271633241066968036301245706" hpi=hpi"3686229350330315779408744076046048141462704585768218394629518000566526527441023326069207347597075580" hpi=hpi"471652863518287979597654609305869096630589655255927403723118998137478367594287636244561396909150597456" /* 502 digits pi */ pi="3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679" pi=pi"8214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196" pi=pi"4428810975665933446128475648233786783165271201909145648566923460348610454326648213393607260249141273" pi=pi"7245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094" pi=pi"3305727036575959195309218611738193261179310511854807446237996274956735188575272489122793818301194912" resetTime=time('R') do while expression <> '' parse value expression with exp1';'expression select when pos('=',exp1)<>0 then do interpret 'do; 'exp1'; end;' end otherwise interpret 'do; answer='exp1'; end;' select when answer='' then say syntax_diagram() when datatype(answer,'N') then say answer otherwise signal error end end end say "elapsed time:" time('E') return /********************************************************************/ /** routines **/ /********************************************************************/ ERROR:; SYNTAX: say 'Does Not Compute' exit 28 /********************************************************************/ /** functions **/ /********************************************************************/ fx: procedure /* template */ arg x maxDigits=digits() numeric digits maxDigits*2 numeric fuzz maxDigits /* f(x) goes here */ numeric fuzz 0 numeric digits maxDigits return x-0 /********************************************************************/ /** Exponential - Logarithmic **/ /********************************************************************/ exp: procedure /* (a>=0) (n>=0) */ arg a,n select when datatype(n, "W")=1 then x=a**n otherwise x=e(ln(a)*n) end return x ln: procedure /* series methods ( x > 0 ) */ arg x if x<=0 then return "ERROR" maxDigits=digits() numeric digits maxDigits+7 numeric fuzz 7 select when x>80 then do i=0 do while x>=5 i=i+1 x=x/10 end x=ln(x)+i*ln(10) end when x<.5 then do i=0 do while x<.5 i=i+1 x=x*10 end x=ln(x)-i*ln(10) end when x>1.6 then do u=(x-1)/(x+1); x=u; c=1; s=u**2 do forever c=c+1 u=s*u x1=x+u/(2*c-1) if x1=x then leave x=x1 end x=x*2 end otherwise u=(x-1); x=u; c=1; s=u; sign=1 do forever c=c+1 u=u*s sign=sign*(-1) x1=x+sign*u/c if x1=x then leave x=x1 end end numeric fuzz 0 numeric digits maxDigits return x-0 e: procedure /* (all real x) e^x = 1+x+x^2/2!+x^3/3!-x^4/4!... */ arg x maxDigits=digits() select when x<(-5) then do fuzzFactor=abs(x)%5 numeric digits maxDigits*fuzzFactor numeric fuzz maxDigits*(fuzzFactor-1) end otherwise numeric digits maxDigits+7 numeric fuzz 7 end n=x; s=x; x=x+1; d=1; c=1 do forever c=c+1 n=n*s d=d*c x1=x+n/d if x1=x then leave x=x1 end numeric fuzz 0 numeric digits maxDigits return x-0 /********************************************************************/ /** Trigonometric **/ /********************************************************************/ tan: procedure /* (all real x) */ arg x,hyper maxDigits=digits() numeric digits maxDigits*2 numeric fuzz maxDigits if hyper="" then x=sin(x)/cos(x) else x=sinh(x)/cosh(x) numeric fuzz 0 numeric digits maxDigits return x-0 tanh: procedure /* (all real x) */ arg x return tan(x,"h") cos: procedure /* (all real x) cos(x)=1-x^2/2!+x^4/4!-x^6/6!... cosh(x)=1+x^2/2!+x^4/4!+x^6/6!... */ arg x,hyper maxDigits=digits() numeric digits maxDigits*2 numeric fuzz maxDigits n=1; s=x**2; x=1; sign=1; d=1; c=1 select when hyper="" then do forever /* cosine function */ c=c+1 n=n*s sign=(-1)*sign do i=2 to 3 by 1 d=d*(2*c-i) end x1=x+sign*n/d if x1=x then leave x=x1 end otherwise do forever /* hyperbolic cosine function */ c=c+1 n=n*s do i=2 to 3 by 1 d=d*(2*c-i) end x1=x+n/d if x1=x then leave x=x1 end end numeric fuzz 0 numeric digits maxDigits return x-0 cosh: procedure /* (all real x) */ arg x return cos(x,"h") sin: procedure /* (all real x) sin(x)=x/1!-x^3/3!+x^5/5!-x^7/7!... sinh(x)=x/1!+x^3/3!+x^5/5!+x^7/7!... */ arg x,hyper maxDigits=digits() numeric digits maxDigits*2 numeric fuzz maxDigits n=x; s=x**2; sign=1; d=1; c=1 select when hyper="" then do forever /* sine function */ c=c+1 n=n*s sign=(-1)*sign do i=1 to 2 by 1 d=d*(2*c-i) end x1=x+sign*n/d if X1=x then leave x=x1 end otherwise do forever /* hyperbolic sine Function */ c=c+1 n=n*s do i=1 to 2 by 1 d=d*(2*c-i) end x1=x+n/d if X1=x then leave x=x1 end end /*select*/ numeric fuzz 0 numeric digits maxDigits return x-0 sinh: procedure /* (all real x) */ arg x return sin(x,"h") sin_1: procedure expose hpi /* ( x^2<1 -pi/2 < sin_1(x) < pi/2 ) sin_1(x)=x+(x^3/2*3)+(x^5*1*3/2*4*5)+(x^7*1*3*5/2*4*6*7)... */ arg x if x**2 >1 then return "ERROR" maxDigits=digits() numeric digits maxDigits*2 numeric fuzz maxDigits n=x; d=1; s=x**2; c=1; p=0 if abs(x)>(.7854) then do p=1; if x<0 then p=-1 s=1-s; x=sqrt(s); n=x end do forever c=c+1; cc=2*c n=n*(cc-3)*s d=d*(cc-2) x1=x+n/(d*(cc-1)) if x1=x then leave x=x1 end numeric fuzz 0 numeric digits maxDigits select when p>0 then return hpi-x when p<0 then return x-hpi otherwise nop end return x-0 cos_1: procedure expose hpi /* ( x^2<1 0 < cos_1(x) < pi ) */ arg x return hpi-sin_1(x) tan_1: procedure expose hpi /* ( all real x ) */ arg x return hpi-cos_1(x/sqrt(x**2+1)) /********************************************************************/ /** Combinatorial **/ /********************************************************************/ fact: procedure /* n! n=(0,1,2,3...) */ arg n numeric digits 500 m=1 do i=2 to n by 1 m=i*m end return m part: procedure /* Ordered Partition */ arg m parts numeric digits 500 mFact=fact(m) do while parts<>'' parse var parts part parts if datatype(part,'W') & m-part>=0 then do m=m-part mFact=mFact/fact(part) end end return mFact/fact(m) /********************************************************************/ /** PI routines **/ /********************************************************************/ PI: procedure /* AGM Gauss-Legendre Method Crandall: Projects In Scientific Computation */ arg n maxDigits=digits() numeric digits maxDigits+7 numeric fuzz 7 x=sqrt(2); p=2+x; y=sqrt(x) do forever s=sqrt(x) x=(s+1/s)/2 p1=p*((x+1)/(y+1)) if p1=p then leave p=p1 s=sqrt(x) y=((y*s)+(1/s))/(y+1) end numeric fuzz 0 numeric digits maxDigits return p-0 PIa: procedure /* AGM Gauss-Legendre Method */ arg n maxDigits=digits() numeric digits maxDigits+7 numeric fuzz 7 a=1; b=1/sqrt(2); t=1/4; x=1 do i=1 to 100 y=a a=(a+b)/2 b=sqrt(b*y) if a=b then leave t=t-x*(y-a)**2 x=2*x end PI=((a+b)**2)/(4*t) numeric fuzz 0 numeric digits maxDigits return PI-0 /********************************************************************/ /** Roots **/ /********************************************************************/ sqrt: procedure /* (all real x) */ arg x return nrt(x,2) cbrt: procedure /* (all real x) */ arg x return nrt(x,3) nrt: procedure /* ( a>=0 ) ( n>=0 ) */ arg a,n maxDigits=digits() numeric digits maxDigits+7 numeric fuzz 7 if a=1 | a=0 then return a if n=0 then return 1 if a<0 | n<0 then return "ERROR" select when datatype(n, "W" )=1 then do m=n-1 x=bisect(a,n) do forever /* Newton Method x:= x - ( f(x)/f'(x) ) */ x1=(m*x**n+a)/(n*x**m) if x1=x then leave x=x1 end end otherwise x=e(ln(a)/n) end numeric fuzz 0 numeric digits maxDigits return x-0 bisect: procedure /* Bisect Method used to seed nrt() */ arg n,root /* (n>=0) (root: 2,3,4,5,6...) */ numeric digits 12 numeric fuzz 3 a=0; b=n if n<1 then b=1 else a=1 do forever m=(a+b)/2 Fm=m**root-n select when Fm>0 then b=m when Fm<0 then a=m otherwise a=b end if a=b then leave end return b
-- http://mail.python.org/mailman/listinfo/python-list