Mathematics.hel
Introduction
REXX does not have an 'include' facility nor 'arbitrary precision' mathematical functions out of the
box. In previous 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 (cf '#include', 'import', 'uses' or '::requires').
The use of this tool is highly recommended. But you may always copy the source code into your program
and do the text changes yourself, i.e. change all '[label]' to 'some_name' etc. if present.
Both Regina and ooRexx are supplied with a mathematical library, a DLL based on the C-library. This 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 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 libraries and stand alone files. Other REXX entries will link to this page.
Many sources were helpful while creating these libraries. Credits go to:
- Math functions in REXX: John Brock, Patrick McPhee, several sources
- Code snippets RosettaCode: Gerard Schildberger, Walter Pachl
- Wikipedia International
- Wolfram Mathworld
- Geeks for Geeks
- Online Encyclopedia of Integer Sequences
- 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
For now, all procedures work only with real arguments and deliver real results. No complex arithmetic is supported yet.
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 square root, pi or tangent start having problems at 1000 digits, and the more complex functions as gamma or zeta struggle already with 100 digits.
Basic parameter checks are present. In case of wrong parameters, your program will fail at the proper place.
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 every procedure has 'expose glob.' coded to make it available. Some procedures also use extra stems, like prim. or flag.
As you might guess, there are many cross references between the libraries.
Usage
(Preferred) Use the low profile pre processor (include pieces of code in a REXX program): Low profile REXX pre processor.
Mind the cross refs: if you include Numbers, big chance you'll also need Functions and Constants. Settings and Abend are recommended: they provide a nice condition handling.
or
Copy and paste (parts) of the libraries in your program.
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. For a proper working it's highly recommended to set condition novalue (signal on novalue: traps wrong arguments) and resetting a global stem (glob. = "": prevents novalue condition on global variables).
Complex
The first version of 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'.
Cabs: Absolute value (modulus, magnitude) Cadd: Add Carg: Argument (phase) Cconj: Conjugate Ccueq: Roots of cubic ax^3+bx^2+cx+d = 0 Cdiv: Divide Cequ: Equality Ceval: Evaluate polynomial with real coefficients Cim: Imaginary part Cinv: Invert Cmod: Modulus (absolute value, magnitude) Cmul: Multiply Cneg: Negate Cnorm: Normalize Complex: Complex? Cpol2form: Polar -> formula Crect: Polar -> rectangular Cpower: Integer power Cqueq: Roots of quartic ax^4+bx^3+cx^2+dx+e = 0 Cre: Real part Crect2form: Rectangular -> formula Cpol: Rectangular -> polar Cround: Round to specified decimals Cscale: Scale Csci: Convert to scientific format Csqeq: Roots of square ax^2+bx+c = 0 Csqrt: Square root Cstd: Convert to standard format Csub: Subtract
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.
Apery: Apery constant Artin: Artin constant Backhouse: Backhouse constant Bernstein: Bernstein constant Bloch: Bloch constant Bronze: Bronze ratio constant = positive root of x^2-3x-1 Brun: Brun constant Cahen: Cahen constant Capacity: Logarithmic capacity of the unit disk constant Catalan1: Catalan constant Chaitin: Chaitin constant Champernowne: Champernowne constant Conway2: Conway constant = real root of x^71-x^69-2x^68...-6x^2+3x-6 Copeland: Copeland-Erdos constant Devicci: DeVicci constant = positive root of 4x^8-28x^6-7x^4+16x^2+16 Dottie: Dottie constant = root of Cos(x) - x Dubois: Second Dubois-Reymond constant E: Euler constant Embree: Embree-Trefethen constant Erdos1: Erdos-Borwein constant Erdos2: Erdos-Tenenbaum-Ford constant Euler: Euler-Mascheroni constant Feigenbaum1: Feigenbaum first constant Feigenbaum2: Feigenbaum second constant Feller: Feller-Tornier constant Foias: Foias constant Fraction: First continued fraction constant Fransen: Fransen-Robertson constant Gauss: Gauss constant Gelfond1: Gelfond constant Gelfond2: Gelfond-Schneider constant Gieseking: Gieseking constant Glaisher: Glaisher-Kinkelin constant Golden: Golden ratio constant = root of x^2-x-1 Goldenangle: Golden angle constant Golomb1: Golomb constant Gompertz: Gompertz constant Hafner: Hafner-Sarnak-McCurley constant Heath: Heath-Brown-Moroz constant Hermite: Second Hermite constant Kepler: Kepler-Bouwkamp constant Khinchin: Khinchin constant Komornik: Komornik-Loreti constant Landau1: Landau-Ramanujan constant Landau2: Landau constant Laplace: Laplace limit constant Lebesgue2: Lebesgue constant Lemniscate: Lemniscate constant Levy1: Levy-Khinchin constant Levy2: Second Levy constant Lieb: Lieb constant Ln2: Natural log of 2 constant Ln4: Natural log of 4 constant Ln8: Natural log of 8 constant Ln10: Natural log of 10 constant Loch: Loch constant Magicangle: Magic angle constant Meissel: Meissel-Mertens constant Mills: Mills constant Mrb: MRB constant Nielsen: Nielsen-Ramanujan constant Niven: Niven constant Omega: Omega constant = LambertW0(1) = root of x*e^x-1 Paperfolding: Paper folding constant Parabolic: Universal parabolic constant Pi: Pi constant Plastic: Plastic ratio constant = real root of x^3-x-1 Porter: Porter constant Prouhet: Prouhet-Thue-Morse constant Ramanujan: Ramanujan constant Recifibo: Reciprocal Fibonacci constant Robbins: Robbins constant Salem: Salem constant = largest positive root of x^10+x^9-x^7-x^6-x^5-x^4-x^3+x+1 Sierpinski: Sierpinski constant Silver: Silver ratio constant = positive root of x^2-2x-1 Soldner: Soldner constant Somos: Somos quadratic recurrence constant Sqrt2: Square root of 2 constant Sqrt3: Square root of 3 constant Sqrt5: Square root of 5 constant Stephens: Stephens constant Supergolden: Super golden ratio constant = real solution of x^3-x^2-1 Taniguchi: Taniguchi constant Tau1: Tau constant = 2*pi Tetranacci2: Tetranacci constant = root of x^4-x^3-x^2-x-1 Tribonacci2: Tribonacci constant = root of x^3-x^2-x-1 Twinprimes: Twin primes constant Vanderpauw: Van der Pauw constant Viswanath: Viswanath constant Wallis: Wallis constant = real root of x^3-2x-5 Weierstrass: Weierstrass constant Zscore: Z-score 97.5 percentile constant
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.
Ackermann: Ackermann's function Acos: Arc cosine Acosh: Arc cosine hyperbolic Acot: Arc cotangent Acoth: Arc cotangent hyperbolic Acsc: Arc cosecant Acsch: Arc cosecant hyperbolic Agmean: Arithmetic geometric mean Aliquot: Aliquot function = Sum of all divisors of xx including 1 Alog: Antilog = 10^x Amean: Arithmetic mean Asec: Arc secant Asech: Arc secant hyperbolic Asin: Arc sine Asinh: Arc sine hyperbolic Atan: Arc tangent Atanh: Arc tangent hyperbolic Atan2: Arc tangent correct quadrant Beta: Beta Ceil: Ceiling Comb: Combination = binomial coefficient Cos: Cosine Cosh: Cosine hyperbolic Cot: Cotangent Coth: Cotangent hyperbolic Csc: Cosecant Csch: Cosecant hyperbolic Curt: Cubic root = x^(1/3) Deg: Radians->degrees Dfact: Double factorial = n!! Digamma: Digamma Digitprod: Digital product = product(digits) Digitroot: Digital root Digitsum: digitsum = sum(digits) Divisor: Divisor = sum(Divisors(x)^y) Dxgamma: First derivative of Gamma Dxzeta: First derivative of Zeta Erf: Error Erfc: Error complementary Even: Is a number even? Exp: Exponential = e^xx Fact: Integer factorial = n! Factorial: Real factorial = x! Ffact: Falling factorial Floor: Floor Frac: Fractional part Gamma: Gamma Gcd: Greatest common divisor Gmean: Geometric mean Half: Is a number half integer? Isqrt: Integer square root = Floor(xx^(1/2)) Lambda1: Dirichlet lambda Lambertw0: Lambert W0 Lambertwm1: Lambert W-1 Lcm: Least common multiple function Ln: Natural logarithm Log: Briggs logarithm Logxy: Logarithm xx base yy Mant: Mantissa Nroot: Nth root = x^(1/y) Number: Is xx a number? Odd: Is a number odd? Perm: Permutations Pow: Power = x^y Powmod: Power modulus = x^(y mod z) Prim: Primorial = p# Primecount: Prime count = Pi() function Primeest: Nth prime number estimate Primorial: Primorial = p# Qurt: Quartic root = x^(1/4) Rad: Degrees->radians Radical: Radical = product of unique prime factors Rand: Random number Repunit: Repeated 1's Rfact: Rising factorial Round: Round to specified decimals Sci: Convert to scientific format Sec: Secant Sech: Secant hyperbolic Sigma: Sigma = Sum of all divisors of x including 1 and x Sin: Sine Sinh: Sine hyperbolic Sqrt: Square root = x^(1/2) Std: Convert to standard format Tan: Tangent Tanh: Tangent hyperbolic Tau2: Ramanujan Tau Totient: Euler's totient function = Phi Trigamma: Trigamma Whole: Is a number integer? Xpon: Exponent Zeta: Zeta
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 quite slow as the numbers grow. The full list:
Abundant: Is a number abundant? Alcuin: Alcuin numbers Almostprime: Is a number almost k-prime? Arithmetic: Is a number arithmetic? Bell: Bell numbers Beraha: Beraha numbers Bernoulli: Bernoulli numbers Cake: Cake numbers Catalan2: Catalan numbers Caterer: Lazy caterer's numbers Central: Central binomial coefficient numbers Chowla: Chowla numbers Composite: Is a number composite? Conway1: Conway look-and-say numbers Coprime: Are 2 numbers coprime? Cullen: Cullen numbers Deficient: Is a number deficient? Derangement: Derangement numbers Favard: Favard numbers Fermat: Fermat numbers Ffactor: First prime factor Fibonacci: Fibonacci numbers Goldbach: Goldbach numbers Golomb2: Golomb-Silverman numbers Gould: Gould numbers Gregory1: Gregory numbers 1 Gregory2: Gregory numbers 2 Harmonic: Harmonic numbers Highcomposite: Is a number highly composite? Home: Home prime numbers Jacobsthal: Jacobsthal numbers Kaprekar: Is a number Kaprekar? Lah: Lah numbers Lambda2: Lambda numbers Lebesgue1: Lebesgue numbers Leonardo: Leonardo numbers Lucas: Lucas numbers Magic: Magic numbers Metallic: Metallic ratio numbers Moebius: Moebius numbers Motzkin: Motzkin numbers Narayana: Narayana cows numbers Padovan: Padovan numbers Partition: Partition numbers Pell1: Pell numbers Pell2: Pell-Lucas companion numbers Perfect: Is a number perfect? Perrin: Perrin numbers Persistence: Additive persistence Pollardrho: Find one prime factor Practical: Is a number practical? Prime: Is a number prime? Pronic: Pronic numbers Recaman: Recaman numbers Semiprime: Is a number semi prime? Sorting: Sorting numbers Stirling1: Stirling numbers 1 Stirling2: Stirling numbers 2 Sylvester: Sylvester numbers Tetranacci1: Tetranacci numbers Thue: Thue-Morse numbers Tribonacci1: Tribonacci numbers Ulam: Ulam numbers Wedderburn: Wedderburn numbers Woodall: Woodall numbers ZigZag: Zigzag alternating permutations numbers
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'. For speed, internal processing is done mostly with arrays and output is not automatically converted to a string or formula. For these conversions some procedures are present in this library.
Padd: Addition Parr2form: Array -> Formula Parr2lst: Array -> List Pdif: Differentiation Pdiv: Long division (in progress) Peval: Evaluation Plst2arr: List -> Array Plst2form: List -> Formula Pmul: Multiplication Pnorm: Normalize coefs Ppow: Exponentiation Psub: Polynomial subtraction
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'.
Rabs: Absolute value Radd: Add Rdiv: Divide Rinv: Invert Rmul: Multiply Rneg: Negate Rpow: Power Rrat: Float -> Rational Rsimp: Simplify Rsub: Subtract
Roots
For equations of the second to third 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'. You may leave out the lower order terms, taking value 0. So x^2-2x=0 is coded as '1 -2'.
Cbeq: Roots of cubic ax^3+bx^2+cx+d = 0 Lneq: Roots of linear ax+b = 0 Sqeq: Roots of square ax^2+bx+c = 0
Sequences
These procedures 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.
Abundants: Abundant number sequence Additives: Additive prime sequence Amicables: Amicable number sequence Arithmetics: Arithmetic number sequence Carmichaels: Carmichael 3 strong prime sequence Chowlas: Chowla number sequence Combinations: Combination sequence Composites: Composite number sequence = not prime Cubans: Cuban prime sequence Cubics: Cubic prime sequence Cyclops: Cyclop number sequence Deficients: Deficient number sequence Divisors: Divisors of an integer Efactors: Prime factors with exponent Emirps: Reversed primes sequence Erdoss: Erdos prime sequence Euclids: Euclid-Mullin number sequence Extras: Extra prime sequence Factors: Prime factors Fareys: Farey fraction sequence Frobeniuss: Frobenius prime sequence Giugas: Giuga number sequence Hammings: Hamming number sequence Highcomposites: Highly composite number sequence Humbles: Humble number sequence Kaprekars: Kaprekar number sequence Perfects: Perfect number sequence Practicals: Practical number sequence Primes: Prime sequence Primorials: Primorial sequence Quadratics: Quadratic prime sequence Reversables: Reversable prime sequence Totients: Euler's totient number sequence Ufactors: Unique prime factors
Generic Quicksort
If you are willing to adopt a specific structure of your stems, this procedure is able to sort a 'composite stem', on 1 or more key tails, syncing 0 or more data tails. Any number of keys or data is allowed. Sorting may be ascending or descending, string or numeric. The procedure is highly optimized to handle both small and large stems.
The mentioned structure goes as follows. Let's use a 'database' approach. A (classic relational) database has tables, each table has columns. Some of these columns may be key columns, other may be data columns. Represent this in REXX with stems:
- table. (a stem for each table)
- table.0 = n (number of rows)
- table.col1.x (first column with row number)
- table.col2.x (second column with row number)
- table.col3.x (third column with row number)
- etc
Of course put your own names for 'table', 'col1' etc. This naming convention closely mimics the fully qualified names for tables and columns in SQL, and shows clearly the relation between the tails as belonging to the head 'table.'. Exposing only 'table.' to a procedure makes the number of rows and all columns available.
A call to this generic quicksort might look like
table = 'table.'; keys = 'key1. key2.' ; data = 'data1.'
call <your name> table,keys,data
...
include Quicksort [label]=<your name>
Keys and data specify your key and data columns, separated by a space. The table and at least 1 key must be given, but data may be empty. Always include the period in your names.
Default the sort is numeric ascending. By specifying special values with your include of this routine you may create copies that behave different:
- [lt]=> [gt]=< for a descending sort
- [lt]=<< [eq]=== [gt]=>> for a ascending string sort
- [lt]=>> [eq]=== [gt]=<< for a descending string sort
For a real world example see [states, cities and population] (Realistic example, Version 3).
Customized Quicksorts
Above procedure is beautiful and generic, but also slow compared to customized sorts (by about a factor 4). Therefore I include here predefined procedures for various numbers of keys and columns. If you have big stems (say 100,000 items or more), you may want to use these faster sorts. There are 12 templates for 1-3 key columns and 0-3 data columns, named Quicksortkd (k = number of key columns, d = number of data columns), i.e. Quicksort21 will sort on 2 keys, while syncing 1 data. For each combination keys/data you'll have a separate procedure generated. A call to such a customized routine might look like
call <your name>
...
include Quicksort21 [label=<your name> [table]=<your stem.> [key1]=<first key.> [key2]=<second key.> [data1]=<data to sync.>
Always include the period in your names. Defaults for and control of ascending/descending/numeric/string is the same as for the generic sort.
For a real world example see [states, cities and population] (Realistic example, Version 2).
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:
/* abend.rex */
Main:
/* \Rex\Tools\Settings.inc */
/* Global settings snippet - Build 5 Dec 2024 */
/* (C) Paul van den Eertwegh 2024 */
call Lines 'dummy'
signal on halt name Abend
signal on notready name Abend
signal on novalue name Abend
signal on syntax name Abend
parse version version; parse source . . source
glob. = ''; call Time('r')
/* \Rex\Tools\Settings.inc */
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
/* \Rex\Tools\Abend.inc */
/* Debug handler library - Build 5 Dec 2024 */
/* (C) Paul van den Eertwegh 2024 */
Abend:
/* Settings voor routine Abend */
Trace off
signal off halt
signal off notready
signal off novalue
signal off syntax
/* Condition info */
parse version version; parse source . . source
s_ = Strip(Sourceline(sigl)); c_ = Condition('c'); d_ = Condition('d')
/* Source info */
if rc <> 16 then do
say
say 'Rexx :' version
say 'Source :' source
end
say 'Line :' sigl s_
/* Get variables from source line */
call GetVariables
/* And show them */
call ShowVariables
/* Condition message */
select
when d_ = 'ARGUMENT' then
c_ = 'Argument outside domain or invalid'
when c_ = 'HALT' then
c_ = 'Program interrupted'
when c_ = 'NOTREADY' then
c_ = 'File does not exist or is in use'
when c_ = 'NOVALUE' then
c_ = 'Variable has no value'
when c_ = 'SYNTAX' then
c_ = 'Runtime error'
otherwise
c_ = ''
end
/* Additional info */
if rc <> 16 then do
if c_ <> '' then
say 'Signal :' c_
if d_ <> 'ARGUMENT' then do
if Datatype(rc) = 'NUM' then
if rc > 0 then
say 'Error :' rc Errortext(rc)
if d_ <> '' then
if d_ <> 'SIGINT' then
say 'Reason :' d_
end
end
say
/* Force display of call tree */
signal on novalue name IgnoreError16
say IgnoreError16
return
Debug:
/* Debug info */
s_ = Strip(Sourceline(sigl)); d_ = Condition('d')
/* Source info */
say
say 'Line :' sigl s_
/* Get variables from source line */
call GetVariables
/* And show them */
call ShowVariables
return
GetVariables:
/* Collect variables from source line */
v_. = 0
s_ = Translate(s_," ","+-*|<>,;=/\%()'")
do i_ = 1 to Words(s_)
w_ = Word(s_,i_)
if Symbol(w_) = 'VAR' then do
call Variable
if Pos('.',w_) > 0 then do
t_ = Translate(w_," ",".")
do j_ = 2 to Words(t_)
w_ = Word(t_,j_)
if Symbol(w_) = 'VAR' then
call Variable
end
end
end
end
return
Variable:
/* Save variable */
do k_ = 1 to v_.0
if w_ = v_.k_ then
leave
end
if k_ > v_.0 then do
v_.k_ = w_; v_.0 = k_
end
return
ShowVariables:
/* Show values */
do i_ = 1 to v_.0
v_ = v_.i_; a_ = Value(v_)
if d_ = 'ARGUMENT' then
say 'Arg :' v_ '=' '"'a_'"'
else
say 'Var :' v_ '=' '"'a_'"'
end
return
/* \Rex\Tools\Abend.inc */
/* -------------------------------------------------- */
/* Summary Lines Timestamp */
/* -------------------------------------------------- */
/* abend.rex 78 1 Nov 2024 15:41:27 */
/* \Rex\Tools\Settings.inc 10 5 Dec 2024 10:23:03 */
/* \Rex\Tools\Abend.inc 111 5 Dec 2024 10:12:52 */
/* -------------------------------------------------- */
/* 0.02 seconds 199 5 Dec 2024 10:33:06 */
/* -------------------------------------------------- */
If I comment out all the trap condition settings in this program 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" 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" 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" 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" 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" 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" 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" 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" 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" 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" 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" 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" 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'.