home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 18 REXX / 18-REXX.zip / rxxmath.zip / rxxmath.cmd next >
OS/2 REXX Batch file  |  1996-11-19  |  20KB  |  687 lines

  1. /* REXX RXXMATH v1.3 (19 Nov 1996); Copyright 1992, 1996 by John Brock
  2.  
  3. For help, type "rxxmath" without arguments at the command line.
  4.  
  5. */
  6.  
  7. signal on halt /* First instruction, because we could halt anytime! */
  8. signal on syntax /* Mainly in case we hit internal numeric limits. */
  9. signal on novalue /* Shouldn't ever happen. */
  10.  
  11. parse source . cmd? . .
  12. cmd? = cmd? = "COMMAND" /* Were we called as a command? */
  13. dgt = digits() /* Default for precision argument. */
  14. glb.0dgt = dgt /* (Save it). */
  15. extra_dgt? = 1 /* Increase internal precision above requested value? */
  16.  
  17. /* Get precision, function name, and arguments from argument list.  */
  18. /* Note that the "extra_dgt?" variable may be taken from argument   */
  19. /* list.  This is an "undocumented interface", which is used to     */
  20. /* avoid a second and redundant increase in internal precision      */
  21. /* when RXXMATH calls itself recursively through the CALC function. */
  22. if cmd? /* Do basic argument parsing. */
  23.   then parse arg func x y . 1 . str /* (str is for CALC). */
  24.   else parse arg func 1 _extra_dgt? _dgt, x 1 str, y
  25. select /* Deal with possible non-basic argument parsing. */
  26.   when cmd?
  27.     then if datatype(func, "N") /* First argument is precision. */
  28.       then parse arg dgt func x y . 1 . . str
  29.       else if func = ""
  30.         then signal helpmsg /* No arguments, so print help message. */
  31.   when (_extra_dgt? == 0 | _extra_dgt? == 1) & datatype(_dgt, "N")
  32.     then parse arg extra_dgt? dgt, func, x 1 str, y
  33.   otherwise if datatype(func, "N") /* First argument is precision. */
  34.     then parse arg dgt, func, x 1 str, y
  35.   end
  36. func = space(translate(func))
  37. dgt = dgt / 1
  38.  
  39. /* Validate precision argument. */
  40. if \datatype(dgt, "W") | dgt < 0
  41.   then call error "Illegal value for precision:" dgt
  42.  
  43. /* List of functions supported by RXXMATH (and available in CALC). */
  44. funcs = "FACT PERM COMB SQRT POW LOG EXP LN PI SIN COS TAN",
  45.   "COT SEC CSC ARCSIN ARCCOS ARCTAN ARCCOT ARCSEC ARCCSC CALC"
  46.  
  47. /* "SCAN" and "PULLSCAN" are special functions which support CALC. */
  48. /* They are "undocumented", and not listed in the function list    */
  49. /* (which means that they are not available as CALC functions).    */
  50. /* Note that dgt = 0 has a special meaning for these functions.    */
  51. if \cmd? & (func = "SCAN" | func = "PULLSCAN") then do
  52.   if func = "PULLSCAN" then do
  53.     if y \= "LIT" & queued() + lines() = 0 then say x
  54.     parse pull x
  55.     end
  56.   exit scan(funcs, extra_dgt?, dgt, x)
  57.   end
  58.  
  59. /* Validate function name. */
  60. if func = "" then call error "Function name is missing."
  61. if words(func) \= 1 | wordpos(func, funcs) = 0
  62.   then call error "Invalid function name:" func
  63. glb.0func = func /* Save function name for use in error messages. */
  64.  
  65. /* If precision is zero then use default value. */
  66. if dgt = 0 then dgt = glb.0dgt
  67.  
  68. /* Remove excess precision from arguments. */
  69. numeric digits dgt
  70. if datatype(x, "N")
  71.   then x = x / 1
  72.   else x = space(x)
  73. if datatype(y, "N")
  74.   then y = y / 1
  75.   else y = space(y)
  76.  
  77. numeric digits intdgt(dgt, extra_dgt?) /* Set internal precision. */
  78.  
  79. select /* Call appropriate function. */
  80.   when func == "FACT" then z = fact(x)
  81.   when func == "PERM" then z = perm(x, y)
  82.   when func == "COMB" then z = comb(x, y)
  83.   when func == "SQRT" then z = sqrt(x)
  84.   when func == "POW" then z = pow(x, y)
  85.   when func == "LOG" then z = log(x, y)
  86.   when func == "EXP" then z = exp(x)
  87.   when func == "LN" then z = ln(x)
  88.   when func == "PI" then z = pi()
  89.   when func == "SIN" then z = sin(x)
  90.   when func == "COS" then z = cos(x)
  91.   when func == "TAN" then z = tan(x)
  92.   when func == "COT" then z = cot(x)
  93.   when func == "SEC" then z = sec(x)
  94.   when func == "CSC" then z = csc(x)
  95.   when func == "ARCSIN" then z = arcsin(x)
  96.   when func == "ARCCOS" then z = arccos(x)
  97.   when func == "ARCTAN" then z = arctan(x)
  98.   when func == "ARCCOT" then z = arccot(x)
  99.   when func == "ARCSEC" then z = arcsec(x)
  100.   when func == "ARCCSC" then z = arccsc(x)
  101.   /* The interpretive CALC function is supported by RXXMATHI,      */
  102.   /* leaving RXXMATH eligible for REXX compilation (if available). */
  103.   when func == "CALC" then do
  104.     call "RXXMATHI" str, extra_dgt? & str = "",,
  105.       intdgt(dgt, extra_dgt? & str \= ""), errmsg(),,
  106.       "RXXMATH interactive mode -- enter any valid REXX instruction:"
  107.     if symbol("result") = "VAR" /* Process output from CALC function. */
  108.       then if str = "" /* If we were in interactive CALC mode... */
  109.         then exit result /* ...then return result immediately. */
  110.         else z = result /* Process non-interactive result further. */
  111.       else if str = ""
  112.         then exit /* A simple exit is OK from interactive mode... */
  113.         else call error /* ...but otherwise means there was an error. */
  114.     end
  115.   otherwise call error "Function name is valid but not implemented."
  116.   end
  117.  
  118. numeric digits dgt /* Reset precision to requested value. */
  119. z = z / 1 /* Format result, removing trailing zeros. */
  120.  
  121. /* All done, so return result to user! */
  122. if \cmd? then exit z
  123. say z
  124. exit
  125.  
  126.  
  127. /* Given a string, scan it for function calls that can be executed */
  128. /* by RXXMATH, and replace them with direct calls to RXXMATH.  For */
  129. /* example, "exp(2)" might become "RXXMATH(0 digits(), 'EXP', 2)". */
  130. /* Note that the calls to RXXMATH that are constructed here supply */
  131. /* extra_dgt? as part of the first argument.  This is really the   */
  132. /* only place where this should ever happen.                       */
  133. scan: procedure expose glb.
  134. parse arg funcs, extra_dgt?, dgt, str
  135. if dgt = 0 then dgt = "digits()"
  136.  
  137. do i = 1 to words(funcs) /* Loop thru list of supported functions. */
  138.   func = translate(word(funcs, i)) /* Select a function. */
  139.   pos = 0 /* Start at the beginning of the string. */
  140.   do forever /* Look for multiple occurrences. */
  141.     prepstr = prepstr(str, max(1, pos), '"' "'", '"' "'")
  142.     pos = pos(func"(", prepstr, pos + 1) /* Needn't find ")". */
  143.     if pos = 0 then leave /* Function not found in string. */
  144.     if pos > 1
  145.       then if symbol(substr(prepstr, pos - 1, 1)) \= "BAD"
  146.         then iterate /* (What we found was part of another function!) */
  147.     /* Supported function found, so replace it with call to RXXMATH. */
  148.     str = insert("'RXXMATH'("extra_dgt? dgt", '"func"', ",,
  149.       delstr(str, pos, length(func) + 1), pos - 1)
  150.     end
  151.   end
  152.  
  153. return str
  154.  
  155.  
  156. /* Take a string, uppercase it, and blank out any quoted       */
  157. /* substrings (to avoid unnecessary function call expansions). */
  158. /* Input is string, starting position, left delimiters, and    */
  159. /* corresponding right delimiters.                             */
  160. /* Example: "ln(2) + calc('pi()')" ==> "ln(2) + calc('    ')". */
  161. prepstr: procedure expose glb.
  162. arg str, start, lftdlm, rgtdlm
  163.  
  164. do while start <= length(str)
  165.  
  166.   /* Find the nearest left delimiter, if any. */
  167.   parse value (length(str) + 1) with lftpos lft rgt
  168.   do i = 1 to words(lftdlm)
  169.     pos = pos(word(lftdlm, i), str, start)
  170.     if pos > 0 & pos < lftpos then do
  171.       lft = word(lftdlm, i)
  172.       rgt = word(rgtdlm, i)
  173.       lftpos = pos
  174.       end
  175.     end
  176.  
  177.   if lft = "" then leave /* No left delimiter found. */
  178.  
  179.   /* Blank out string between left and right delimiter (if any). */
  180.   lftpos = lftpos + length(lft)
  181.   rgtpos = pos(rgt, str, lftpos)
  182.   if rgtpos = 0 then rgtpos = length(str) + 1
  183.   str = overlay(copies(" ",  rgtpos - lftpos), str, lftpos)
  184.   start = rgtpos + length(rgt)
  185.   end
  186.  
  187. return str
  188.  
  189.  
  190. /* Determine how numeric digits should be set internally.           */
  191. /* If extra_dgt? = 1 then we double requested precision, using      */
  192. /* the default setting of numeric digits to set a lower limit (so   */
  193. /* that a requested precision of 2, for example, won't result in an */
  194. /* unreasonably low internal precision of 4).  If extra_dgt? = 0    */
  195. /* then we just use the requested precision, whatever it is.        */
  196. intdgt: procedure expose glb.
  197. arg dgt, extra_dgt?
  198. if extra_dgt?
  199.   then return 2 * max(dgt, glb.0dgt) /* Extended precision. */
  200.   else return dgt /* Unextended precision. */
  201.  
  202.  
  203. /* Find value of x!. */
  204. fact: procedure expose glb.
  205.  
  206. x = arg_ok(arg(1), "W >=0")
  207.  
  208. y = 1
  209. do n = 2 to x
  210.   y = y * n
  211.   end
  212.  
  213. return y
  214.  
  215.  
  216. /* Find the number of permutations of x things taken y at a time. */
  217. perm: procedure expose glb.
  218.  
  219. x = arg_ok(arg(1), "W >=0")
  220. y = arg_ok(arg(2), "W >=0")
  221. if x < y then call error "Illegal arguments:" x "<" y
  222.  
  223. z = 1
  224. do n = (x - y) + 1 to x
  225.   z = z * n
  226.   end
  227.  
  228. return z
  229.  
  230.  
  231. /* Find the number of combinations of x things taken y at a time. */
  232. comb: procedure expose glb.
  233.  
  234. x = arg_ok(arg(1), "W >=0")
  235. y = arg_ok(arg(2), "W >=0")
  236. if x < y then call error "Illegal arguments:" x "<" y
  237.  
  238. if x - y < y then y = x - y /* Adjust y. */
  239.  
  240. z = 1
  241. do n = (x - y) + 1 to x
  242.   z = z * n
  243.   end
  244.  
  245. do n = 2 to y
  246.   z = z / n
  247.   end
  248.  
  249. return z
  250.  
  251.  
  252. /* Find square root using Newton's method. */
  253. sqrt: procedure expose glb.
  254.  
  255. x = arg_ok(arg(1), ">=0")
  256.  
  257. if x = 0 then return 0
  258. if x = 1 then return 1
  259.  
  260. /* Adjust number so it is between 1 and 100. */
  261. i = ilog(100, x, 1, 100)
  262. x = x * 100 ** -i
  263.  
  264. y = x / 2
  265. old = y
  266. do n = 1
  267.   y = ((x / y) + y) / 2
  268.   if y = old then leave
  269.   old = y
  270.   end
  271.  
  272. return y * 10 ** i
  273.  
  274.  
  275. /* Find x to the power of y. */
  276. pow: procedure expose glb.
  277.  
  278. x = arg_ok(arg(1))
  279. y = arg_ok(arg(2))
  280.  
  281. if y = 0 then return 1
  282. if datatype(y, "W") & x \= 0 then return x ** y
  283. if x <= 0 then do
  284.   if x < 0 then call error,
  285.     "Non-integer power of a negative number:" "(" || x || ") **" y
  286.   if y < 0 then call error "Zero taken to a negative power:" y
  287.   return 0
  288.   end
  289.  
  290. /* If possible use square root function (for speed). */
  291. if abs(y // 1) = 0.5 then return sqrt(x) ** sign(y) * x ** (y % 1)
  292.  
  293. return exp(y * ln(x))
  294.  
  295.  
  296. /* Find the log of y base x. */
  297. log: procedure expose glb.
  298. return ln(arg(2)) / ln(arg_ok(arg(1), "\=1"))
  299.  
  300.  
  301. /* Find e to the power of x. */
  302. exp: procedure expose glb.
  303.  
  304. x = arg_ok(arg(1))
  305.  
  306. i = x % 1
  307. if abs(x - i) > 0.5 then i = i + sign(x)
  308. x = x - i /* Adjust x for quick convergence. */
  309.  
  310. y = sum_e(x)
  311. if i \= 0 then y = y * sum_e(1) ** i
  312.  
  313. return y
  314.  
  315.  
  316. /* Find the natural log of x (using sum of -((-1)**n)*(x-1)**n/n). */
  317. ln: procedure expose glb.
  318.  
  319. x = arg_ok(arg(1), ">0")
  320.  
  321. if x = 10 then do /* Special assist for ln(10). */
  322.   m = "2.30258509299404568401799145468436420760110148862877"
  323.   y = format(m)
  324.   if y \== m then return y
  325.   end
  326.  
  327. /* Adjust x between 0.5 and 1.5 (for convergence). */
  328. i = ilog(sum_e(1), x, 0.5, 1.5)
  329. x = x * sum_e(1) ** -i
  330.  
  331. x = x - 1
  332. f = -1
  333. y = 0
  334. old = y
  335. do n = 1
  336.   f = -f * x
  337.   y = y + f / n
  338.   if y = old then leave
  339.   old = y
  340.   end
  341.  
  342. return y + i
  343.  
  344.  
  345. /* Find e to the power of x (using the usual series expansion).    */
  346. /* If x = 1 then save value of e (because it may be needed again). */
  347. sum_e: procedure expose glb.
  348. parse arg x
  349.  
  350. if x = 1 then do /* Return hard coded value if precision allows. */
  351.   if symbol("glb.0e") = "VAR" then return glb.0e
  352.   e = "2.71828182845904523536028747135266249775724709369996"
  353.   glb.0e = format(e)
  354.   if glb.0e \== e /* Does hard coded value exceed internal precision? */
  355.     then return glb.0e
  356.   end
  357.  
  358. y = 1
  359. f = 1
  360. old = y
  361. do n = 1
  362.   f = f * x / n
  363.   y = y + f
  364.   if y = old then leave
  365.   old = y
  366.   end
  367.  
  368. if x = 1 then glb.0e = y /* Save value of e. */
  369.  
  370. return y
  371.  
  372.  
  373. /* Return i such that bot <= (y / (x ** i)) <= top.               */
  374. /* Conditions are x, y, top, bot > 0, x \= 1, top >= bot          */
  375. /* This procedure works by repeatedly looking for factors of the  */
  376. /* form x ** (2 ** j) which are divided out of y to move it       */
  377. /* toward the intended range (without overshooting, if possible). */
  378. /* Note: if x > 1 then ilog(x, y, 1, x) = trunc(log(x, y)).       */
  379. ilog: procedure expose glb.
  380. arg x, y, bot, top
  381.  
  382. high = y > top
  383. sign = 1 - 2 * (high \= (x > 1))
  384.  
  385. i = 0
  386. do while high & y > top | \high & y < bot
  387.  
  388.   f = x
  389.   do j = -1
  390.     q = y * f ** -sign
  391.     if j >= 0 & (high & q < top | \high & q > bot) then leave
  392.     f = f * f
  393.     g = q
  394.     end
  395.  
  396.   y = g
  397.   i = i + sign * 2 ** j
  398.   end
  399.  
  400. return i
  401.  
  402.  
  403. /* Calculate (and save) pi, using arcsin(1/2) = pi/6. */
  404. /* Saved or hard coded value of pi used if possible.  */
  405. pi: procedure expose glb.
  406.  
  407. if symbol("glb.0pi") = "VAR" then return glb.0pi
  408.  
  409. pi = "3.14159265358979323846264338327950288419716939937511"
  410. glb.0pi = format(pi)
  411.  
  412. if glb.0pi == pi then glb.0pi = 6 * arcsin(0.5)
  413.  
  414. return glb.0pi
  415.  
  416.  
  417. /* Find the sine of x (usual series expansion). */
  418. sin: procedure expose glb.
  419.  
  420. x = arg_ok(arg(1), "TRIG")
  421.  
  422. x = x // (2 * pi()) /* Adjust between pi and -pi, for convergence. */
  423. if abs(x) > pi() then x = x - sign(x) * 2 * pi()
  424.  
  425. f = x
  426. y = x
  427. x = x ** 2
  428. old = y
  429. do n = 2 by 2
  430.   f = -f * x / (n * (n + 1))
  431.   y = y + f
  432.   if y = old then leave
  433.   old = y
  434.   end
  435.  
  436. return y
  437.  
  438.  
  439. /* Find the cosine of x (usual series expansion). */
  440. cos: procedure expose glb.
  441.  
  442. x = arg_ok(arg(1), "TRIG")
  443.  
  444. x = x // (2 * pi()) /* Adjust between pi and -pi, for convergence. */
  445. if abs(x) > pi() then x = x - sign(x) * 2 * pi()
  446.  
  447. f = 1
  448. y = 1
  449. x = x ** 2
  450. old = y
  451. do n = 2 by 2
  452.   f = -f * x / (n * (n - 1))
  453.   y = y + f
  454.   if y = old then leave
  455.   old = y
  456.   end
  457.  
  458. return y
  459.  
  460.  
  461. /* Find the tangent of x. */
  462. tan: procedure expose glb.
  463.  
  464. x = arg_ok(arg(1))
  465.  
  466. y = cos(x)
  467. if y = 0 then call error "Result is infinite."
  468.  
  469. return sin(x) / y
  470.  
  471.  
  472. /* Find the cotangent of x. */
  473. cot: procedure expose glb.
  474.  
  475. x = arg_ok(arg(1))
  476.  
  477. y = sin(x)
  478. if y = 0 then call error "Result is infinite."
  479.  
  480. return cos(x) / y
  481.  
  482.  
  483. /* Find the secant of x. */
  484. sec: procedure expose glb.
  485.  
  486. x = arg_ok(arg(1))
  487.  
  488. y = cos(x)
  489. if y = 0 then call error "Result is infinite."
  490.  
  491. return 1 / y
  492.  
  493.  
  494. /* Find the cosecant of x. */
  495. csc: procedure expose glb.
  496.  
  497. x = arg_ok(arg(1))
  498.  
  499. y = sin(x)
  500. if y = 0 then call error "Result is infinite."
  501.  
  502. return 1 / y
  503.  
  504.  
  505. /* Find the inverse sine of x (usual series expansion). */
  506. arcsin: procedure expose glb.
  507.  
  508. x = arg_ok(arg(1), "ABS<=1")
  509.  
  510. /* Avoid region where series converges slowly.  (Note recursion!) */
  511. if abs(x) >= 0.75 then return sign(x) * arccos(sqrt(1 - x ** 2))
  512.  
  513. f = x
  514. y = x
  515. x = x ** 2
  516. old = y
  517. do n = 2 by 2
  518.   f = f * x * (n - 1) / n
  519.   y = y + f / (n + 1)
  520.   if y = old then leave
  521.   old = y
  522.   end
  523.  
  524. return y
  525.  
  526.  
  527. /* Find the inverse cosine of x. */
  528. arccos: procedure expose glb.
  529. return pi() / 2 - arcsin(arg(1))
  530.  
  531.  
  532. /* Find the inverse tangent of x. */
  533. arctan: procedure expose glb.
  534.  
  535. x = arg_ok(arg(1))
  536.  
  537. return arcsin(x / sqrt(x ** 2 + 1))
  538.  
  539.  
  540. /* Find the inverse cotangent of x. */
  541. arccot: procedure expose glb.
  542.  
  543. x = arg_ok(arg(1))
  544.  
  545. return arccos(x / sqrt(x ** 2 + 1))
  546.  
  547.  
  548. /* Find the inverse secant of x. */
  549. arcsec: procedure expose glb.
  550.  
  551. x = arg_ok(arg(1), "ABS>=1")
  552.  
  553. return sign(x) * arccos(1 / x)
  554.  
  555.  
  556. /* Find the inverse cosecant of x. */
  557. arccsc: procedure expose glb.
  558.  
  559. x = arg_ok(arg(1), "ABS>=1")
  560.  
  561. if x > 0
  562.   then return arcsin(1 / x)
  563.   else return -(pi() + arcsin(1 / x))
  564.  
  565.  
  566. /* Validate function arguments against a given lists of tests. */
  567. arg_ok: procedure expose glb.
  568. parse arg x, test_list
  569. test_list = translate(test_list)
  570.  
  571. /* Argument must always exist and be a valid number. */
  572. if x = "" then call error "Missing argument."
  573. if \datatype(x, "N") then call error "Illegal argument:" x
  574.  
  575. if wordpos("W", test_list) > 0 /* Must be whole number. */
  576.   then if \datatype(x, "W")
  577.     then call error "Illegal argument:" x
  578. if wordpos(">=0", test_list) > 0 /* Must be >= zero. */
  579.   then if x < 0
  580.     then call error "Argument < 0:" x
  581. if wordpos(">0", test_list) > 0 /* Must be > zero. */
  582.   then if x <= 0
  583.     then call error "Argument <= 0:" x
  584. if wordpos("\=1", test_list) > 0 /* Must not equal one. */
  585.   then if x = 1
  586.     then call error "Illegal argument:" x
  587. if wordpos("ABS<=1", test_list) > 0 /* Absolute value must be <= one. */
  588.   then if abs(x) > 1
  589.     then call error "Argument is > 1 or < -1:" x
  590. if wordpos("ABS>=1", test_list) > 0 /* Absolute value must be >= one. */
  591.   then if abs(x) < 1
  592.     then call error "Argument is < 1 and > -1:" x
  593.  
  594. /* To accurately calculate trigonometric functions the absolute value */
  595. /* of the argument must be small enough that we can subtract from it  */
  596. /* a multiple of 2 * pi and get an accurate result between pi and     */
  597. /* -pi.  Actually the test used here is too rigorous.  In most (but   */
  598. /* not all) cases we get a completely accurate result by using        */
  599. /* digits() % 2 (instead of digits() % 4).  But then, who really      */
  600. /* needs sine or cosine of very large numbers anyway?                 */
  601. if wordpos("TRIG", test_list) > 0
  602.   then if abs(x) >= 10 ** (digits() % 4)
  603.     then call error "Argument is too large:" x
  604.  
  605. return x
  606.  
  607.  
  608. halt: call error errortext(4)
  609.  
  610.  
  611. syntax: call error errortext(rc)
  612.  
  613.  
  614. novalue: call error "NOVALUE at line" sigl
  615.  
  616.  
  617. /* Print error message and exit. */
  618. error: procedure expose glb.
  619. if arg(1, "E") then say errmsg(arg(1))
  620. parse source . cmd? .
  621. if cmd? = "COMMAND"
  622.   then exit 1 /* Error return code is 1 when called as a command. */
  623.   else exit   /* If called as function caller will blow up. */
  624.  
  625.  
  626. /* Create an error message. */
  627. errmsg: procedure expose glb.
  628. parse source . . pname .
  629. errmsg = "Error in" pname
  630. if symbol("glb.0func") = "VAR" then errmsg = errmsg "("glb.0func")"
  631. errmsg = errmsg "--"
  632. if arg(1, "E") then errmsg = errmsg arg(1)
  633. return errmsg
  634.  
  635.  
  636. /* Print out a help message. */
  637. helpmsg:
  638.  
  639. say "      RXXMATH v1.3 -- Arbitrary Precision Math Functions for REXX"
  640. say "                   Copyright 1992, 1996 by John Brock"
  641. say
  642. say "Syntax:     Command line:   rxxmath [digits] function [x [y]]"
  643. say "            REXX function:  rxxmath([digits,] function [,x [,y]])"
  644. say
  645. say "Where:      digits     is the desired precision of the result"
  646. say "                         (if omitted or zero the NUMERIC DIGITS"
  647. say "                          default, which should be 9, is used)"
  648. say "            function   is the name of a supported function"
  649. say "            x, y       are arguments to the function"
  650. say
  651. say "Functions:  FACT(x)    --  Factorial of x"
  652. say "            PERM(x,y)  --  Permutations of x by y"
  653. say "            COMB(x,y)  --  Combinations of x by y"
  654. say "            SQRT(x)    --  Square root of x"
  655. say "            POW(x,y)   --  x to the power of y"
  656. say "            LOG(x,y)   --  Log of y base x"
  657. say "            EXP(x)     --  e to the power of x"
  658. say "            LN(x)      --  Natural log of x"
  659. say "            PI()       --  Value of pi"
  660. say "            SIN(x)     --  Sine of x"
  661. say "            COS(x)     --  Cosine of x"
  662. say "            TAN(x)     --  Tangent of x"
  663. say "            COT(x)     --  Cotangent of x"
  664. say "            SEC(x)     --  Secant of x"
  665. say "            CSC(x)     --  Cosecant of x"
  666. say "            ARCSIN(x)  --  Inverse sine of x"
  667. say "            ARCCOS(x)  --  Inverse cosine of x"
  668. say "            ARCTAN(x)  --  Inverse tangent of x"
  669. say "            ARCCOT(x)  --  Inverse cotangent of x"
  670. say "            ARCSEC(x)  --  Inverse secant of x"
  671. say "            ARCCSC(x)  --  Inverse cosecant of x"
  672. say "            CALC(x)    --  Calculate the value of an expression"
  673. say "                             (e.g. '1 + exp(pi() / 2)')"
  674. say
  675. say "Notes:      When RXXMATH is called as a command with no arguments"
  676. say "              it prints a help message to the screen."
  677. say "            All trigonometric function arguments are in radians."
  678. say "            When invoked from the command line RXXMATH prints its"
  679. say "              result to the screen and returns 0 (or 1 on error)."
  680. say "            When called as a REXX function RXXMATH returns its"
  681. say "              result to REXX (on error no result is returned)."
  682. say "            When the CALC function is called without an argument"
  683. say "              RXXMATH goes into interpretive REXX calculator mode"
  684. say "              (change REXX variable ""prompt"" to alter prompt)."
  685.  
  686. exit
  687.