RxxMath
Автор: John Brock
Дата: 1996
RXXMATH v1.3 -- Arbitrary Precision Math Functions for REXX
Copyright 1992, 1996 by John Brock
RXXMATH is an extremely easy-to-use math package which may be called as
an external routine from REXX or invoked from the command line. RXXMATH
is true to the spirit of REXX math in that it will calculate results to
arbitrary precision. Because RXXMATH is itself written entirely in REXX
it should port essentially unchanged to any environment which supports
REXX. (RXXMATH was originally written for VM/CMS, but the author has
also run it under MVS/TSO, IBM PC DOS 7, and OS/2). Note that along
with the basic math functions RXXMATH has an interpretative calculator
function which may be used to evaluate complex mathematical expressions,
or even used as a interactive "REXX shell".
This RXXMATH distribution is for OS/2, and includes the files:
RXXMATH.CMD -- the main program
RXXMATHI.CMD -- support for the interpretative REXX calculator function
RXXMATH.DOC -- this documentation file
RXXMATH is unsupported freeware, and is provided "as is", with no
warranties of any sort, express or implied. RXXMATH may be freely
distributed in any format, provided no alterations are made to the files
(other than what may be necessary to port RXXMATH to a new environment)
and no restrictions are placed on further distribution. Users may
modify RXXMATH at their convenience, as long as the copyright notices
are retained and the modified version is not distributed publicly.
Comments are welcome, and may be sent to jbrock@panix.com.
The following functions are supported:
FACT(x) -- Factorial of x
PERM(x,y) -- Permutations of x by y
COMB(x,y) -- Combinations of x by y
SQRT(x) -- Square root of x
POW(x,y) -- x to the power of y
LOG(x,y) -- Log of y base x
EXP(x) -- e to the power of x
LN(x) -- Natural log of x
PI() -- Value of pi
SIN(x) -- Sine of x
COS(x) -- Cosine of x
TAN(x) -- Tangent of x
COT(x) -- Cotangent of x
SEC(x) -- Secant of x
CSC(x) -- Cosecant of x
ARCSIN(x) -- Inverse sine of x
ARCCOS(x) -- Inverse cosine of x
ARCTAN(x) -- Inverse tangent of x
ARCCOT(x) -- Inverse cotangent of x
ARCSEC(x) -- Inverse secant of x
ARCCSC(x) -- Inverse cosecant of x
CALC(x) -- Calculate the value of an expression
(e.g. '1 + exp(pi() / 2)')
When invoked from the command line, RXXMATH has the format:
+----------------------------------------------------------------------+
| RXXMATH [digits] function [x [y]] |
+----------------------------------------------------------------------+
When called as a function from REXX, RXXMATH has the format:
+----------------------------------------------------------------------+
| RXXMATH([digits,] function [,x [,y]]) |
+----------------------------------------------------------------------+
Where: digits is the desired precision of the result
(if omitted or zero the NUMERIC DIGITS
default, which should be 9, is used)
function is the name of a supported function
x, y are arguments to the function
Examples:
1. From the command line, find the square root of 2 to 40 places:
rxxmath 40 sqrt 2 (or rxxmath 40 pow 2 0.5)
result: 1.41421356237309504880168872420969807857
2. Find the square root of 2 to 9 places (the default):
rxxmath sqrt 2
result: 1.41421356
3. From within REXX, print the base 10 log of 5 to 40 places:
say rxxmath(40, "LOG", 10, 5)
result: 0.6989700043360188047862611052755069732318
4. From REXX, print the base 10 log of 5 to 9 places:
say rxxmath("LOG", 10, 5)
result: 0.698970004
5. From REXX, print 1 plus e to the power of pi/2, to 50 places:
say rxxmath(50, "CALC", "1 + exp(pi() / 2)")
result: 5.8104773809653516554730356667038331263901708746645
6. From the command line, find "1 + exp(pi() / 2)" to 9 places:
rxxmath calc 1 + exp(pi() / 2)
result: 5.81047738
7. Enter interactive REXX calculator mode (a "REXX shell"):
rxxmath calc
result: RXXMATH interactive mode -- enter any valid REXX instruction:
a = 1 + exp(pi() / 2)
RXXMATH interactive mode -- enter any valid REXX instruction:
say a
5.8104774
RXXMATH interactive mode -- enter any valid REXX instruction:
numeric digits 50
RXXMATH interactive mode -- enter any valid REXX instruction:
b = 1 + exp(pi() / 2); say b
5.8104773809653516554730356667038331263901708746648
RXXMATH interactive mode -- enter any valid REXX instruction:
prompt = "New prompt:"
New prompt:
numeric digits 9
New prompt:
say pi() - ln(23)
0.00609843
New prompt:
say calc("pi() - ln(23)")
0.00609843766
New prompt:
say calc(pi() - ln(23))
0.00609843
New prompt:
exit
Notes:
If invoked without arguments from the command line, RXXMATH will print a
help message.
When invoked as a command RXXMATH normally prints its result to the
screen and returns 0. If there is an error it prints an error message
and returns 1. When called as a REXX function RXXMATH normally returns
its result to REXX and prints nothing. If there is an error RXXMATH
prints an error message and returns no value to REXX. This will cause
the SYNTAX condition to be raised, which is consistent with the behavior
of REXX built-in functions when given bad arguments. However if
necessary you can avoid raising the SYNTAX condition on error by calling
RXXMATH as a subroutine, rather than a function.
All trigonometric function arguments are in radians.
In general the numeric arguments to an RXXMATH function may be any legal
REXX numbers, of any size and precision. If an argument has more
significant digits than the requested precision of the result the
argument will be rounded before use. Of course an attempt to use a
number outside the range of a given function (e.g., SQRT(-2) or
FACT(3.3)) will result in an error. Arguments to the trigonometric
functions may not be of arbitrary size, but must have an absolute value
which is < 10 ** (precision % 2). So, for example, using a precision of
9 you could calculate sin(9999), but trying to calculate sin(10000)
would result in an error. In the unlikely event that you really need to
calculate the sine or cosine of a very large number it can be done by
increasing the size of the of the precision argument until the above
condition is met (which may however result in an unacceptably long
execution time).
RXXMATH uses REXX's arbitrary precision arithmetic to calculate its
results, so naturally if an implementation of REXX does not support this
feature of the language then RXXMATH's ability to return high precision
results will be limited. RXXMATH sets its internal precision twice as
high as requested by the user, so if, for example, the highest precision
a given implementation of REXX will support is 100, then the highest
precision the user may request from RXXMATH is 50.
Some performance considerations. When the precision is <= 25 RXXMATH
can use hard coded values for e and pi (which are used internally a
lot), and ln(10) (which provides a special boost for log base 10
calculations). The POW function knows when it is being asked to take a
square root (e.g., RXXMATH("POW", 0.25, -1.5) = 8), and uses the
considerably faster SQRT function when appropriate. And RXXMATH can
recognize situations that REXX can deal with directly, such as integer
powers, so that, for example, RXXMATH("POW", 2.5, 10) will execute much
faster than RXXMATH("POW", 2.5, 10.1).
All calculations are done in the main program, RXXMATH, which may be
compiled if a REXX compiler is available. RXXMATHI (which is called
only by RXXMATH, never by the user) supports the interpretative REXX
calculator function ("CALC"), and because it uses the "interpret"
statement it may not be compiled. Note that RXXMATH and RXXMATHI call
each other when the CALC function is used, so this function will not
work unless they are placed in locations where they can find each other
automatically.
The CALC function takes a character string and interprets it as a REXX
expression, using the RXXMATH math functions with names and arguments as
listed above (e.g., "exp(4)" is replaced by the appropriate call to
RXXMATH itself). In addition to the math functions supplied by RXXMATH,
the expression may contain any REXX built-in functions or any external
functions which return a numeric result.
If you call the CALC function without any arguments you will go into the
interactive REXX calculator mode ("REXX shell"). From there you can
issue any valid REXX instructions, using any of the math functions
supported by RXXMATH, as well as any other functions or commands usable
from within REXX. When you enter interactive mode you will be prompted
for input. The prompt string is contained in the REXX variable
"prompt", and may be altered or suppressed by changing or dropping that
variable. In addition, if there are lines in the external data queue
the prompt is suppressed while those lines are read and executed. The
"return" or "exit" instructions will take you out of interactive mode,
and may be used to return a value if desired.
The basic RXXMATH math functions are all highly accurate, and the CALC
function inherits their accuracy, but because the CALC function
evaluates arbitrary mathematical expressions in a straightforward
numerical way (rather than symbolically) the need for error analysis is
not eliminated. Consider the following methods for calculating the
expression "pi() - ln(23)", using the default precision of 9.
1. a = rxxmath("PI") - rxxmath("LN", 23) /* CALC is avoided. */
2. queue 'a = pi() - ln(23)'
queue 'return a'
b = rxxmath("CALC") /* Interactive CALC (queued instructions). */
3. c = rxxmath("CALC", "pi() - ln(23)") /* Non-interactive CALC. */
Methods 1 and 2 are exactly equivalent, and set a = b = 0.00609843.
Method 3 gives more precision, setting c = 0.00609843766. In the first
two cases pi() and ln(23) are both calculated (accurately) to 9 places,
and their difference is taken, giving a result with fewer than 9 digits
of precision. In case 3 RXXMATH calculates both pi() and ln(23) to 18
places, takes the difference, and then rounds the final result to 9
significant digits before returning it, which gives a better result.
Note that CALC is itself a perfectly legitimate RXXMATH function, and
therefore can be evaluated by CALC. For example, you can call CALC
non-interactively while in RXXMATH interactive mode, as was done in
Example 7 above. Just make sure the argument is a quoted string, or
your expression will be evaluated too early and the benefit lost.
History:
v1.3 (19 Nov 1996)
The name of the package was changed from RXMATH to RXXMATH to avoid a
name conflict with an unrelated package of math functions for REXX.
The negation operator was changed from "^" (caret) to "\" (backslash).
The code that prints a help message when RXXMATH is invoked without
arguments was changed so that it no longer reads the message from the
leading comment using SOURCELINE(). This means the the message will
still print even if RXXMATH is compiled and the comments stripped out.
Some built-in REXX functions -- DIGITS(), WORDPOS(), and LINES() -- were
not available when the code was first written, and so were coded
explicitly into the program. These have been stripped out, on the
assumption that these functions should be included as built-ins in all
current REXX implementations.
The documentation was partially rewritten.
Other minor changes, mostly for readability.
v1.2 (15 Oct 1992)
Various changes to make the code SAA compliant.
v1.1 (7 Sep 1990)
Minor changes for running under MVS/TSO.
v1.0 (8 Sep 1989)
Original version for VM/CMS.