Jump to content

Mathematics.hel

From Rosetta Code

Introduction

REXX does not have an 'include' facility nor 'arbitrary precision' mathematical functions out of the box. In many older REXX entries it was custom the have all needed routines and procedures copied into the program. This is cumbersome and redundant. Newer entries redirect to
Libraries and Pre processor and Include clause how to use them.

At the end of each entry you'll find several 'include' clauses, showing the libraries that the program needs (just like '#include', 'import', 'uses' or '::requires').

Both Regina and ooRexx are supplied with a mathematical library, a DLL based on the C-library. This library supports some basic math functions and a few constants, up to 16 digits precision. For many tasks on RosettaCode this is not sufficient.

In 2024 I (Zeddicus) started posting on RosettaCode and found the copy-and-paste WoW to get a runnable program annoying. Therefore I'll gather all procedures I have until now and present them here in several modules and stand alone files. Other REXX entries will link to this page. It's not quite correct to name these modules 'libraries'. They are just REXX source code that becomes part of your program.

Many sources were helpful while creating these libraries. Credits go to:

  • Math functions in REXX: John Brock, Patrick McPhee, several other sources
  • Code snippets RosettaCode: Gerard Schildberger, Walter Pachl
  • Wikipedia International
  • Wolfram Mathworld
  • Geeks for Geeks
  • Online Encyclopedia of Integer Sequences
  • Google
  • ChatGPT4
  • Numerical methods at work: Henrik Vestermark
  • Numerical recipes: Press et al
  • Various other books and internet math sources and online calculators
  • And my own research and try-outs

General remarks

Most procedures work only with real arguments and deliver real results. However, there are special libraries capable to perform actions on other types of data: Complex (complex arithmetic and functions), Polynomial (polynomial arithmetic and functions) and Rational (working with fractions).
Out of the box, REXX can work with arbitrary precision, thus also these procedures, using your current numeric digits setting. However, basic functions such as Sqrt, Pi or Tan start becoming slower at 1000 digits and more, and the more complex functions as Gamma or Zeta struggle already with 100 digits. For most results you may expect the least significant digit (from your numeric digits setting) to be off at most 1. However, this cannot be guaranteed, so be careful to rely on all digits.
Each procedure performs its own parameter checking. In case of wrong parameters, your program will fail at the proper place. This ensures that a procedure may be used stand-alone, not relying on the caller for its parameters. Though this introduces a lot of overhead, it makes the modules more robust.
All routines are coded with the 'procedure' clause, meaning all variables within are local. They communicate via the parameters. However, sometimes it's handy or needed to use global variables (store multiple results, memorization). For this the stem 'glob.' is used, and many procedures have 'expose glob.' coded to make it available. Some procedures also use extra stems, like prim. or cueq. Exposed stems always follow the 'xxxx.' naming convention.
As you might expect, there are many MANY cross references between the modules.

Usage

Use the low profile pre processor (include pieces of code in a REXX program): Low profile REXX pre processor.
Using this tool is highly recommended. Besides including external code, it also handles conditions in a neat way. I recommend copying and running the self-extractor in a folder of your choice: it extracts all modules and programs including demos, the pre processor and documentation.
The documentation includes a list of all modules, a list of all procedures/routines, an extract of all comments in the source and other useful reports.

or (not recommended, after extraction):

Copy and paste (parts) of the libraries/procedures in your program.
Add a line

glob. = ''

in your main routine.
Many REXX entries use this technique, leading to a lot of duplicated code. After resolving all cross refs, your program will run without the preprocessor.

Complex

This library supports the basic arithmetic operations, modulus, argument, conjugate, rectangular<->polar and more. Complex numbers a+bi are coded as string (list): 'a b'. You may leave out b, but not a. Thus 2 = '2', 2i = '0 2' and 2+2i = '2 2'. Procedures Cadd, Cdiv, Cmul and Csub accept any number of arguments, thus facilitating repeated addition etc. All the usual trigo functions are present, with their inverses and hyperbolic forms. Exp, Ln and Pow(er) are also supported. Several tools such as polynomial evaluation and formatting are included.

Constants

A whole bunch of mathematical constants: Pi, E, Euler-Mascheroni and a lot more. Up to 100 digits, these constants are predefined and thus given directly. Above 100 digits, under availability of a acceptable fast algorithm, the constant is calculated. All procedures in this library have no parameters.

Functions

Here we have the well known set of trigonometric, hyperbolic, exponential and logarithmic functions and their inverses. And of course functions like Square/Cubic/Quartic/Nth root. Some 'higher' functions are also included: Beta, Gamma, Zeta and a few more. Arguments for the trig functions is always in radians, maybe you like to use Deg or Rad to convert values. Several functions more related to number theory are present. This library accepts only real arguments.

Numbers

These are procedures belonging to the field 'number theory': all kinds of numbers, combinations, factors, divisors, and more. Most procedures expect a number as parameter, some two numbers or even three. Many of these procedures become slower as the numbers grow.

Polynomial

This set of procedures deal with 'polynomial processing', such as add, exponentiate, convert to a formula and more. The external representation of a polynomial is as a list, implemented in a string. The adopted convention is alike most text books and the internet: coefficients are stored highest power first and missing terms included as 0. Thus x^4+2x^2+x = '1 0 2 1 0' and x-1 = '1 -1'.

Rational

One of the tasks on RosettaCode is 'Rational arithmetic'. The most important procedures from this field are included here. Besides the second parameter of Rpower, all arguments in and out have the form 'numerator denominator'. The denominator may be left out, taking value 1. Thus 1/2 = '1 2' and 2/1 = 2 = '2'.

Roots

For equations of the first to fourth degree solutions in closed form (formulas) are possible. Procedures for these equations are present here. The input follows the convention as described in Polynomial: so solving x^2-3x+2=0 is represented by parameter '1 -3 2'. Complex number support comes with its own procedures.

Sequences

These procedures also belong to the category 'number theory'. They return the count of found numbers, and the numbers itself in stems to be processed by the calling program. There might be a counterpart in Numbers: for example Prime(x) tests the primality of x and Primes(x) collects all primes up to x.

Math

This module contains the code of all above modules, so 'include Math' will make everything available for your program. Using Math, you don't have to bother about cross references and missing includes. It's about 8k lines, so may have some effect on the performance.

Abnormal end handler

This is a standard handler of the REXX conditions causing a program to stop, such as SYNTAX, NOVALUE, NOTREADY and HALT. There are 2 parts: a code snippet Settings to set the conditions and a library Abend to handle them. Include Settings always at the beginning of your program or main procedure if present. And include Abend at the end. The handler also traps wrong arguments.

Consider below program. Name it Abend.rex if want to try it.

Main:
include Settings
say version; say 'Abnormal program end handler'; say
call TriggerSyntax
call TriggerNovalue
call TriggerNotready
call TriggerHalt
call TriggerCalls
call TriggerArgs
exit

TriggerSyntax:
procedure
say 'Trigger syntax...'
f = 1; g = 2; h = 3
say f+g h/0 g-h
return

TriggerNovalue:
procedure
say 'Trigger no value...'
f = 1; g = 2; h = 3; i = absent; j = 1/h
return

TriggerNotready:
procedure
say 'Trigger not ready...'
file = 'absent'
call Stream file,'c','open read'
return

TriggerHalt:
procedure
say 'Trigger halt...'
do forever
   f = 1; g = 2; h = 3
end
return

TriggerCalls:
procedure
say 'Trigger calls...'
call Sub1 123.456
return

TriggerArgs:
procedure
say 'Trigger arguments...'
call Sub3 -1
return

Sub1:
procedure
arg xx
xx = xx/2
call Sub2 xx
return

Sub2:
procedure
arg xx
xx = xx/4
g = xx/absent
return

Sub3:
procedure
arg xx
call Sub4 xx
return

Sub4:
procedure
arg xx
if xx < 0 then say abend
return

include Abend

Using 'rexx|regina run Abend' will generate Runner.rex, check this to see how it works. After being generated, you may run Runner.rex the useal way, i.e. 'rexx|regina runner'. If I comment out all the trap condition settings in Runner.rex and run the 6 calls in Main: one by one, then I get the standard error handling:

REXX-Regina_3.9.6(MT) 5.00 29 Apr 2024
Abnormal program end handler

Trigger syntax...
    31 +++    say f+g h/0 g-h
    20 +++ call TriggerSyntax
Error 42 running "C:\Rex\Rosetta\runner.rex", line 31: Arithmetic overflow/underflow
Error 42.3: Arithmetic overflow; divisor must not be zero

Trigger no value...

Trigger not ready...

Trigger halt...
    51 +++       g = 2
    23 +++    call TriggerHalt
Error 4 running "C:\Rex\Rosetta\runner.rex", line 51: Program interrupted

Trigger calls...
    79 +++          g = xx/absent
    72 +++       call Sub2 xx
    59 +++    call Sub1 123.456
    24 +++ call TriggerCalls
Error 41 running "C:\Rex\Rosetta\runner.rex", line 79: Bad arithmetic conversion
Error 41.2: Non-numeric value ("ABSENT") to right of arithmetic operation "/"

Trigger arguments...
ARGUMENT

ooRexx output is similar. The 'NOVALUE' condition is standard not triggered. Very likely your program will fail somewhere else. The 'NOTREADY' condition is standard also not triggered. Your program might fail elsewhere or produce no output. An advantage of this standard approach is the showing of the 'call stack', i.e. Runner -> Abend -> call Trigger... -> clause in error. This helps very much while debugging.
Using customized 'signal on' trapping, this call stack information is not available. Therefore I added a trick in routine Abend to force the display of the call stack.
Argument errors are trapped by clauses like 'if xx < 0 then say argument'. This raises the NOVALUE condition, which is recognized by routine Abend, as seen below.

Now, the same action with all condition traps enabled, produces following output for Regina:

REXX-Regina_3.9.6(MT) 5.00 29 Apr 2024
Abnormal program end handler

Trigger syntax...

Rexx   : REXX-Regina_3.9.6(MT) 5.00 29 Apr 2024
Source : C:\Rex\Rosetta\Runner.rex
Line   : 32 say f+g h/0 g-h
Var    : f = "1"
Var    : g = "2"
Var    : h = "3"
Digits : 9
Signal : Runtime error
Error  : 42 Arithmetic overflow/underflow
Reason : Error 42.3: Arithmetic overflow; divisor must not be zero

   166 +++    say IgnoreError16
    20 +++ call TriggerSyntax
Error 16 running "C:\Rex\Rosetta\runner.rex", line 166: Label not found
Error 16.1: Label "IGNOREERROR16" not found

Trigger no value...

Rexx   : REXX-Regina_3.9.6(MT) 5.00 29 Apr 2024
Source : C:\Rex\Rosetta\Runner.rex
Line   : 38 f = 1; g = 2; h = 3; i = absent; j = 1/h
Var    : f = "1"
Var    : g = "2"
Var    : h = "3"
Digits : 9
Signal : Variable has no value
Reason : ABSENT

   166 +++    say IgnoreError16
    21 +++ call TriggerNovalue
Error 16 running "C:\Rex\Rosetta\runner.rex", line 166: Label not found
Error 16.1: Label "IGNOREERROR16" not found

Trigger not ready...

Rexx   : REXX-Regina_3.9.6(MT) 5.00 29 Apr 2024
Source : C:\Rex\Rosetta\Runner.rex
Line   : 45 call Stream file,'c','open read'
Var    : file = "absent"
Digits : 9
Signal : File does not exist or is in use
Reason : absent

   166 +++    say IgnoreError16
    22 +++ call TriggerNotready
Error 16 running "C:\Rex\Rosetta\runner.rex", line 166: Label not found
Error 16.1: Label "IGNOREERROR16" not found

Trigger halt...

Rexx   : REXX-Regina_3.9.6(MT) 5.00 29 Apr 2024
Source : C:\Rex\Rosetta\Runner.rex
Line   : 52 f = 1; g = 2; h = 3
Var    : f = "1"
Var    : g = "2"
Var    : h = "3"
Digits : 9
Signal : Program interrupted

   166 +++       say IgnoreError16
    23 +++    call TriggerHalt
Error 16 running "C:\Rex\Rosetta\runner.rex", line 166: Label not found
Error 16.1: Label "IGNOREERROR16" not found

Trigger calls...

Rexx   : REXX-Regina_3.9.6(MT) 5.00 29 Apr 2024
Source : C:\Rex\Rosetta\Runner.rex
Line   : 79 g = xx/absent
Var    : xx = "15.432"
Digits : 9
Signal : Variable has no value
Reason : ABSENT

   166 +++          say IgnoreError16
    72 +++       call Sub2 xx
    59 +++    call Sub1 123.456
    24 +++ call TriggerCalls
Error 16 running "C:\Rex\Rosetta\runner.rex", line 166: Label not found
Error 16.1: Label "IGNOREERROR16" not found

Trigger arguments...

Rexx   : REXX-Regina_3.9.6(MT) 5.00 29 Apr 2024
Source : C:\Rex\Rosetta\Runner.rex
Line   : 91 if xx < 0 then say argument
Arg    : xx = "-1"
Digits : 9
Signal : Argument outside domain or invalid

   166 +++          say IgnoreError16
    85 +++       call Sub4 xx
    65 +++    call Sub3 -1
    25 +++ call TriggerArgs
Error 16 running "C:\Rex\Rosetta\runner.rex", line 166: Label not found
Error 16.1: Label "IGNOREERROR16" not found

And for ooRexx:

REXX-ooRexx_5.0.0(MT)_64-bit 6.05 23 Dec 2022
Abnormal program end handler

Trigger syntax...

Rexx   : REXX-ooRexx_5.0.0(MT)_64-bit 6.05 23 Dec 2022
Source : C:\Rex\Rosetta\Runner.rex
Line   : 32 say f+g h/0 g-h
Var    : f = "1"
Var    : g = "2"
Var    : h = "3"
Digits : 9
Signal : Runtime error
Error  : 42 Arithmetic overflow/underflow.

Line   : 20 call TriggerSyntax

   168 *-*     say IgnoreError16
Error 16 running C:\Rex\Rosetta\Runner.rex line 168:  Label not found.
Error 16.1:  Label "IGNOREERROR16" not found.

Trigger no value...

Rexx   : REXX-ooRexx_5.0.0(MT)_64-bit 6.05 23 Dec 2022
Source : C:\Rex\Rosetta\Runner.rex
Line   : 38 f = 1; g = 2; h = 3; i = absent; j = 1/h
Var    : f = "1"
Var    : g = "2"
Var    : h = "3"
Digits : 9
Signal : Variable has no value
Reason : ABSENT

Line   : 21 call TriggerNovalue

   168 *-*     say IgnoreError16
Error 16 running C:\Rex\Rosetta\Runner.rex line 168:  Label not found.
Error 16.1:  Label "IGNOREERROR16" not found.

Trigger not ready...

Rexx   : REXX-ooRexx_5.0.0(MT)_64-bit 6.05 23 Dec 2022
Source : C:\Rex\Rosetta\Runner.rex
Line   : 45 call Stream file,'c','open read'
Var    : file = "absent"
Digits : 9
Signal : File does not exist or is in use
Reason : absent

Line   : 22 call TriggerNotready

   168 *-*     say IgnoreError16
Error 16 running C:\Rex\Rosetta\Runner.rex line 168:  Label not found.
Error 16.1:  Label "IGNOREERROR16" not found.

Trigger halt...

Rexx   : REXX-ooRexx_5.0.0(MT)_64-bit 6.05 23 Dec 2022
Source : C:\Rex\Rosetta\Runner.rex
Line   : 52 f = 1; g = 2; h = 3
Var    : f = "1"
Var    : g = "2"
Var    : h = "3"
Digits : 9
Signal : Program interrupted

Line   : 23 call TriggerHalt

   168 *-*     say IgnoreError16
Error 16 running C:\Rex\Rosetta\Runner.rex line 168:  Label not found.
Error 16.1:  Label "IGNOREERROR16" not found.

Trigger calls...

Rexx   : REXX-ooRexx_5.0.0(MT)_64-bit 6.05 23 Dec 2022
Source : C:\Rex\Rosetta\Runner.rex
Line   : 79 g = xx/absent
Var    : xx = "15.432"
Digits : 9
Signal : Variable has no value
Reason : ABSENT

Line   : 72 call Sub2 xx
Var    : xx = "61.728"

Line   : 59 call Sub1 123.456

Line   : 24 call TriggerCalls

   168 *-*     say IgnoreError16
Error 16 running C:\Rex\Rosetta\Runner.rex line 168:  Label not found.
Error 16.1:  Label "IGNOREERROR16" not found.

Trigger arguments...

Rexx   : REXX-ooRexx_5.0.0(MT)_64-bit 6.05 23 Dec 2022
Source : C:\Rex\Rosetta\Runner.rex
Line   : 91 if xx < 0 then say argument
Arg    : xx = "-1"
Digits : 9
Signal : Argument outside domain or invalid

Line   : 85 call Sub4 xx
Var    : xx = "-1"

Line   : 65 call Sub3 -1

Line   : 25 call TriggerArgs

   168 *-*     say IgnoreError16
Error 16 running C:\Rex\Rosetta\Runner.rex line 168:  Label not found.
Error 16.1:  Label "IGNOREERROR16" not found.

Nice layout... and it shows the values of all recognized variables for the line(s) in error. As you see, the ooRexx output differs from the Regina output, but both show the complete call tree from bottom to top. ooRexx happens also to show the arguments in the call tree! The errors 16 may be ignored, that's just the trick to get the call tree information.

It's up to you which method you prefer. You may easily switch between them by (not) using 'include Settings' and 'include Abend'.

Cookies help us deliver our services. By using our services, you agree to our use of cookies.