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 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
  • 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

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'.

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