A precise definition of the arithmetic facilities of the REXX language is given here.
A number in REXX is a character string that includes one or more decimal digits, with an optional decimal point. (See section Exponential Notation for an extension of this definition.) The decimal point may be embedded in the number, or may be a prefix or suffix. The group of digits (and optional decimal point) constructed this way can have leading or trailing blanks and an optional sign (+ or -) that must come before any digits or decimal point. The sign can also have leading or trailing blanks.
Therefore, number is defined as:
>>-+--------+--+------------------+--+-digits--------+----------> '-blanks-' '-sign--+--------+-' +-digits.digits-+ '-blanks-' +-.digits-------+ '-digits.-------' >--+--------+-------------------------------------------------->< '-blanks-'
Note that a single period alone is not a valid number.
Precision is the maximum number of significant digits that can result from an operation. This is controlled by the instruction:
>>-NUMERIC DIGITS--+------------+--;--------------------------->< '-expression-'
The expression is evaluated and must result in a positive whole number. This defines the precision (number of significant digits) to which calculations are carried out. Results are rounded to that precision, if necessary.
If you do not specify expression in this instruction, or if no NUMERIC DIGITS instruction has been processed since the start of a program, the default precision is used. The REXX standard for the default precision is 9.
Note that NUMERIC DIGITS can set values below the default of nine. However, use small values with care--the loss of precision and rounding thus requested affects all REXX computations, including, for example, the computation of new values for the control variable in DO loops.
REXX arithmetic is performed by the operators +, -, *, /, %, //, and ** (add, subtract, multiply, divide, integer divide, remainder, and power), which all act on two terms, and the prefix plus and minus operators, which both act on a single term. This section describes the way in which these operations are carried out.
Before every arithmetic operation, the term or terms being operated upon have leading zeros removed (noting the position of any decimal point, and leaving only one zero if all the digits in the number are zeros). They are then truncated (if necessary) to DIGITS + 1 significant digits before being used in the computation. (The extra digit is a "guard" digit. It improves accuracy because it is inspected at the end of an operation, when a number is rounded to the required precision.) The operation is then carried out under up to double that precision, as described under the individual operations that follow. When the operation is completed, the result is rounded if necessary to the precision specified by the NUMERIC DIGITS instruction.
Rounding is done in the traditional manner. The digit to the right of the least significant digit in the result (the "guard digit") is inspected and values of 5 through 9 are rounded up, and values of 0 through 4 are rounded down. Even/odd rounding would require the ability to calculate to arbitrary precision at all times and is, therefore, not the mechanism defined for REXX.
A conventional zero is supplied in front of the decimal point if otherwise there would be no digit before it. Significant trailing zeros are retained for addition, subtraction, and multiplication, according to the rules that follow, except that a result of zero is always expressed as the single digit 0. For division, insignificant trailing zeros are removed after rounding.
The FORMAT built-in function (see page ***) allows a number to be represented in a particular format if the standard result provided does not meet your requirements.
The basic operators (addition, subtraction, multiplication, and division) operate on numbers as follows.
If either number is 0, the other number, rounded to NUMERIC DIGITS digits, if necessary, is used as the result (with sign adjustment as appropriate). Otherwise, the two numbers are extended on the right and left as necessary, up to a total maximum of DIGITS + 1 digits (the number with the smaller absolute value may, therefore, lose some or all of its digits on the right) and are then added or subtracted as appropriate.
Example:
xxx.xxx + yy.yyyyy
becomes:
xxx.xxx00 + 0yy.yyyyy ------------- zzz.zzzzz
The result is then rounded to the current setting of NUMERIC DIGITS if necessary (taking into account any extra "carry digit" on the left after addition, but otherwise counting from the position corresponding to the most significant digit of the terms being added or subtracted). Finally, any insignificant leading zeros are removed.
The prefix operators are evaluated using the same rules; the operations +number and -number are calculated as 0+number and 0-number, respectively.
The numbers are multiplied together ("long multiplication") resulting in a number that may be as long as the sum of the lengths of the two operands.
Example:
xxx.xxx * yy.yyyyy
becomes:
zzzzz.zzzzzzzz
The result is then rounded, counting from the first significant digit of the result, to the current setting of NUMERIC DIGITS.
For the division:
yyy / xxxxx
the following steps are taken: First the number yyy is extended with zeros on the right until it is larger than the number xxxxx (with note being taken of the change in the power of ten that this implies). Thus, in this example, yyy might become yyy00. Traditional long division then takes place. This might be written:
zzzz *--------- xxxxx | yyy00
The length of the result (zzzz) is such that the rightmost z is at least as far right as the rightmost digit of the (extended) y number in the example. During the division, the y number is extended further as necessary. The z number may increase up to NUMERIC DIGITS+1 digits, at which point the division stops and the result is rounded. Following completion of the division (and rounding if necessary), insignificant trailing zeros are removed.
Following are some examples that illustrate the main implications of the rules just described.
/* With: Numeric digits 5 */
12+7.00 -> 19.00
1.3-1.07 -> 0.23
1.3-2.07 -> -0.77
1.20*3 -> 3.60
7*3 -> 21
0.9*0.8 -> 0.72
1/3 -> 0.33333
2/3 -> 0.66667
5/2 -> 2.5
1/10 -> 0.1
12/12 -> 1
8.0/2 -> 4
The operation rules for the power (**), integer divide (%), and remainder (//) operators follow.
The ** (power) operator raises a number to a power, which may be positive, negative, or 0. The power must be a whole number. (The second term in the operation must be a whole number and is rounded to DIGITS digits, if necessary, as described under Numbers Used Directly by REXX.) If negative, the absolute value of the power is used, and then the result is inverted (divided into 1). For calculating the power, the number is effectively multiplied by itself for the number of times expressed by the power, and finally trailing zeros are removed (as though the result were divided by 1).
In practice (see Note 1 for the reasons), the power is calculated by the process of left-to-right binary reduction. For a**n: n is converted to binary, and a temporary accumulator is set to 1. If n = 0 the initial calculation is complete. (Thus, a**0 = 1 for all a, including 0**0.) Otherwise each bit (starting at the first nonzero bit) is inspected from left to right. If the current bit is 1, the accumulator is multiplied by a. If all bits have now been inspected, the initial calculation is complete; otherwise the accumulator is squared and the next bit is inspected for multiplication. When the initial calculation is complete, the temporary result is divided into 1 if the power was negative.
The multiplications and division are done under the arithmetic operation rules, using a precision of DIGITS + L + 1 digits. L is the length in digits of the integer part of the whole number n (that is, excluding any decimal part, as though the built-in function TRUNC(n) had been used). Finally, the result is rounded to NUMERIC DIGITS digits, if necessary, and insignificant trailing zeros are removed.
The % (integer divide) operator divides two numbers and returns the integer part of the result. The result returned is defined to be that which would result from repeatedly subtracting the divisor from the dividend while the dividend is larger than the divisor. During this subtraction, the absolute values of both the dividend and the divisor are used: the sign of the final result is the same as that which would result from regular division.
The result returned has no fractional part (that is, no decimal point or zeros following it). If the result cannot be expressed as a whole number, the operation is in error and will fail--that is, the result must not have more digits than the current setting of NUMERIC DIGITS. For example, 10000000000%3 requires 10 digits for the result (3333333333) and would, therefore, fail if NUMERIC DIGITS 9 were in effect. Note that this operator may not give the same result as truncating regular division (which could be affected by rounding).
The // (remainder) operator returns the remainder from integer division and is defined as being the residue of the dividend after the operation of calculating integer division as previously described. The sign of the remainder, if nonzero, is the same as that of the original dividend.
This operation fails under the same conditions as integer division (that is, if integer division on the same two terms would fail, the remainder cannot be calculated).
Following are some examples using the power, integer divide, and remainder operators:
/* Again with: Numeric digits 5 */
2**3 -> 8
2**-3 -> 0.125
1.7**8 -> 69.758
2%3 -> 0
2.1//3 -> 2.1
10%3 -> 3
10//3 -> 1
-10//3 -> -1
10.2//1 -> 0.2
10//0.3 -> 0.1
3.6//1.3 -> 1.0
The comparison operators are listed in section Comparison. You can use any of these for comparing numeric strings. However, you should not use ==, \==, ¬==, >>, \>>, ¬>>, <<, \<<, and ¬<< for comparing numbers because leading and trailing blanks and leading zeros are significant with these operators.
A comparison of numeric values is effected by subtracting the two numbers (calculating the difference) and then comparing the result with 0. That is, the operation:
A ? Z
where ? is any numeric comparison operator, is identical with:
(A - Z) ? '0'
It is, therefore, the difference between two numbers, when subtracted under REXX subtraction rules, that determines their equality.
A quantity called fuzz affects the comparison of two numbers. This controls the amount by which two numbers may differ before being considered equal for the purpose of comparison. The FUZZ value is set by the instruction:
>>-NUMERIC FUZZ--+------------+--;----------------------------->< '-expression-'
Here expression must result in a positive whole number or zero. The default is 0.
The effect of FUZZ is to temporarily reduce the value of DIGITS by the FUZZ value for each numeric comparison. That is, the numbers are subtracted under a precision of DIGITS minus FUZZ digits during the comparison. Clearly the FUZZ setting must be less than DIGITS.
Thus if DIGITS = 9 and FUZZ = 1, the comparison is carried out to 8 significant digits, just as though NUMERIC DIGITS 8 had been put in effect for the duration of the operation.
Example:
Numeric digits 5
Numeric fuzz 0
say 4.9999 = 5 /* Displays "0" */
say 4.9999 < 5 /* Displays "1" */
Numeric fuzz 1
say 4.9999 = 5 /* Displays "1" */
say 4.9999 < 5 /* Displays "0" */
The preceding description of numbers describes "pure" numbers, in the sense that the character strings that describe numbers can be very long. For example:
10000000000 * 10000000000
would give
100000000000000000000
and
.00000000001 * .00000000001
would give
0.0000000000000000000001
For both large and small numbers some form of exponential notation is useful, both to make long numbers more readable, and to make execution possible in extreme cases. In addition, exponential notation is used whenever the "simple" form would give misleading information.
For example:
numeric digits 5
say 54321*54321
would display 2950800000 in long form. This is clearly misleading, and so the result is expressed as 2.9508E+9 instead.
The definition of numbers is, therefore, extended as:
>>-+--------+--+------------------+--+-digits--------+----------> '-blanks-' '-sign--+--------+-' +-digits.digits-+ '-blanks-' +-.digits-------+ '-digits.-------' >--+---------------------+--+--------+------------------------->< '-E--+------+--digits-' '-blanks-' '-sign-'
The integer following the E represents a power of ten that is to be applied to the number. The E can be in uppercase or lowercase.
Certain character strings are numbers even though they do not appear to be numeric to the user. Specifically, because of the format of numbers in exponential notation, strings, such as 0E123 (0 raised to the 123 power) and 1E342 (1 raised to the 342 power), are numeric. In addition, a comparison such as 0E123=0E567 gives a true result of 1 (0 is equal to 0). To prevent problems when comparing nonnumeric strings, use the strict comparison operators.
Here are some examples:
12E7 = 120000000 /* Displays "1" */
12E-5 = 0.00012 /* Displays "1" */
-12e4 = -120000 /* Displays "1" */
0e123 = 0e456 /* Displays "1" */
0e123 == 0e456 /* Displays "0" */
The preceding numbers are valid for input data at all times. The results of calculations are returned in either conventional or exponential form, depending on the setting of NUMERIC DIGITS. If the number of places needed before the decimal point exceeds DIGITS, or the number of places after the point exceeds twice DIGITS, exponential form is used. The exponential form REXX generates always has a sign following the E to improve readability. If the exponent is 0, then the exponential part is omitted--that is, an exponential part of E+0 is never generated.
You can explicitly convert numbers to exponential form, or force them to be displayed in long form, by using the FORMAT built-in function (see page FORMAT).
Scientific notation is a form of exponential notation that adjusts the power of ten so a single nonzero digit appears to the left of the decimal point. Engineering notationis a form of exponential notation in which from one to three digits (but not simply 0) appear before the decimal point, and the power of ten is always expressed as a multiple of three. The integer part may, therefore, range from 1 through 999. You can control whether Scientific or Engineering notation is used with the instruction:
.-SCIENTIFIC------------. >>-NUMERIC FORM--+-----------------------+--;------------------>< +-ENGINEERING-----------+ '-+-------+--expression-' '-VALUE-'
Scientific notation is the default.
/* after the instruction */
Numeric form scientific
123.45 * 1e11 -> 1.2345E+13
/* after the instruction */
Numeric form engineering
123.45 * 1e11 -> 12.345E+12
To determine the current settings of the NUMERIC options, use the built-in functions DIGITS, FORM, and FUZZ. These functions return the current settings of NUMERIC DIGITS, NUMERIC FORM, and NUMERIC FUZZ, respectively.
Within the set of numbers REXX understands, it is useful to distinguish the subset defined as whole numbers. A whole number in REXX is a number that has a decimal part that is all zeros (or that has no decimal part). In addition, it must be possible to express its integer part simply as digits within the precision set by the NUMERIC DIGITS instruction. REXX would express larger numbers in exponential notation, after rounding, and, therefore, these could no longer be safely described or used as whole numbers.
As discussed, the result of any arithmetic operation is rounded (if necessary) according to the setting of NUMERIC DIGITS. Similarly, when REXX directly uses a number (which has not necessarily been involved in an arithmetic operation), the same rounding is also applied. It is just as though the number had been added to 0.
In the following cases, the number used must be a whole number, and the largest number you can use is 999999999.
Two types of errors may occur during arithmetic:
This error occurs if the exponential part of a result would exceed the range that the language processor can handle, when the result is formatted according to the current settings of NUMERIC DIGITS and NUMERIC FORM. The language defines a minimum capability for the exponential part, namely the largest number that can be expressed as an exact integer in default precision. Because the default precision is 9, VM supports exponents in the range -999999999 through 999999999.
Because this allows for (very) large exponents, overflow or underflow is treated as a syntax error.
Storage is needed for calculations and intermediate results, and on occasion an arithmetic operation may fail because of lack of storage. This is considered a terminating error as usual, rather than an arithmetic error.