Variable Precision Arithmetic
Version 3.0a
(June 2009)
A Fortran Module
By
J.L.Schonfelder
Contents
2.4 Format inquiry and manipulation
2.4.1 Inquiry on NUMBER
exponent
2.4.2 Inquiry on NUMBER
fraction
2.5 Type conversion procedures
2.5.1 Conversion to type(NUMBER)
by NUM
2.5.2 Conversion to INTEGER
by INT
2.5.3 Conversion to CHARACTER
string by CHAR
2.5.4 Conversion to a formatted CHARACTER
string by EFCHAR
2.5.5 Conversion to a formatted CHARACTER
string by FFCHAR
2.6.1 Addition and Subtraction
2.8 Overloads for numeric intrinsic procedures
2.8.2 Transfer of the sign (SIGN)
This module, written in standard conforming Fortran 95, but making use of the Fortran 2003 extension that allows ALLOCATABLE components, provides a set of facilities for the support of floating-point style of arithmetic that is of variable, and in principle, arbitrary precision. The range of numbers handled is very large. It has been produced to enable applications that require very high and possibly varying numeric precision to be implemented easily. It exploits the semantic-extension data-abstraction capabilities of the Fortran 95 language to define a suitable number data-type and the fundamental arithmetic operations to manipulate numbers of this type. Thus application programs can work with such numbers in ways that are similar to those needed if they were normal REAL values.
The set of facilities provided by this version (3.0) is extended to allow elemental as well as scalar overloads of the basic operations. The set of type conversion routines necessary to allow values to be created and results displayed is slightly extended over those provided in previous versions. The six logical comparison operators are also provided and the most basic of the intrinsic functions are overloaded.
As in version 2 the radix used is chosen to more fully exploit the range of the default integer thus reducing the number of digits necessary to provide a given decimal precision. This improves the efficiency of operations at the expense of some extra complexity in the algorithms. To enable the elemental extension of the operations, the number system is defined so as to have representations for positive and negative overflow, positive and negative underflow, zero, and indeterminate values. The algorithms used for all operations are also defined to propagate such values. Thus operations have no failure conditions and can therefore be made elemental. The occurrence of a numeric exception can only be detected by the occurrence of an unexpected exceptional result.
The major change in this version is in the number representation. This version does not employ an explicit exponent field. Instead the absolute bounds of the stored mantissa are adjusted so that a value is represented as
A = Σ ai R-i for i=e:n
That is the lower bound effectively carries the exponent information and the number of retained digits the precision. This change was made partly to prove that Fortran 95 provided enough control over absolute bounds for them to be used in this way and partly that this representation provides a marginal improvement in both storage and execution efficiency; the latter appears to be approximately 5% at 100D. This 3.0a version employs an allocatable component instead of a pointer. This it is hoped will be both more efficient and less prone to memory leaks.
This version also adds an overload for the SQRT function. This is not elemental for two reasons, SQRT of a negative value has no valid or reasonable exception value so a failure condition must be indicated and this is can not be done within the constraints of an elemental function, and the algorithm used is based on Heron’s rule. This starts with a low accuracy approximation with each iteration doubling the number of correct digits. Efficiency requires the working precision to be varied during the process and again this cannot be done within the elemental rules.
The copyright in both the source code of the module and in this explanatory document rests with the author. However, the module and its documentation may be used freely by any individual or group for charitable, educational or research purposes, provided that such use is acknowledged. If the package is used by a commercial organisation or for commercial gain, this use must be notified to the author in advance. In such cases the author reserves the right to negotiate appropriate terms for such use.
The module is made available in source form and hence it can be freely modified and enhanced by the user. The author requests that any such enhancements that may be generally useful, either by improving the performance of the package, correcting errors or by providing additional functionality, should be communicated to the author. All such enhancements will be considered for possible incorporation in subsequent releases of the package.
The module has been subject to reasonably careful testing by the author and no errors have been found in the released module. However, no guarantee is given or implied that the released module is without fault or is fit for any specific purpose. The author accepts no liability for any damages howsoever caused resulting from any use of this package.
The module is named
VARIABLE_PRECISION_ARITHMETIC
and the facilities of the module can be accessed by the inclusion of the statement
USE VARIABLE_PRECISION_ARITHMETIC
The type is
TYPE NUMBER
INTEGER,ALLOCATABLE
:: sig(:) ! holds the significand
ENDTYPE NUMBER
The interpretation of the type depends on the values of a small number of integer parameters. In the distributed version these are set as appropriate for an IEEE arithmetic system where the default integer is 32 bit, with a range of 9, and HUGE=2147483647. The necessary parameters are declared as
INTEGER,PARAMETER :: maxdecdig=9 ! max number of decimal digits that
! can be represented in a default
integer
! maxdecdig=RANGE(0)
INTEGER,PARAMETER :: radd=8 !
number of decimal digits representable in the
! number radix, radd<maxdecdig and
even
INTEGER,PARAMETER ::
rad=100000000 ! number system radix chosen so that
! rad=10**radd is representable
in a
! default integer
INTEGER,PARAMETER :: rtrad=10000 ! rtrad=SQRT(rad)=10**radd/2
A radix commensurate with 10 is used to simplify conversions to and from a representation of numeric values by character strings in the form of normal decimal notation. The radix is chosen so that it is exactly representable as a default INTEGER and the root of the radix is also an exact power of ten. This enables relatively simple algorithms to be employed for multiplication and division without causing integer overflows.
The value represented by an object of the type(NUMBER) is given by
SUM(sig(i)*rad**(-i)) for i=ex:nx
where: rad is the number system radix, and ex & nx are the lower and upper bounds of the significand; the number of digits retained in the significand nd is nx-ex+1.
The value is normalised so that;
sig(ex)/=0, ABS(sig(i))<rad
and all digits are of the same sign.
For i>nd either sig(i)=0 exactly or the significand has been truncated to retain only nx-ex+1 digits. The truncation length is set by a global variable ndig. Thus the working precision is varied by changing the value of this global variable, ndig. The default working precision set initially guarantees at least 100D accuracy. Values that can be represented exactly with fewer than ndig digits will not carry the extra redundant zero digits.
It should be noted that the maximum allowed exponent is maxexp, (initially set to rad). Numbers larger than this, though in some cases representable are considered too large to be useful. With the above values for the parameters this gives a range of usable normalised values of approximately 10**(-800000000) to 10**(+800000000).
The number system is closed by defining a set of unnormalised values to represent numeric exceptions. These are :
N.B. although the exponent is strictly irrelevant for a zero value it is convenient to give it a defined exponent and an exponent smaller than any normalised or underflowing value has proved sensible. The indeterminant and unknown values all have an exponent larger than any valid or overflowing value. The signed unknown values are defined to represent situations where the result of an operation has no predictable magnitude but the sign is defined. The indeterminant value, which has the same representation as a yet to be defined value, is used to represent results where no valid value can be returned or there is no predictable sign or magnitude for the result; this is effectively a NaN value. All operations are defined to produce either a normalised result or one of these exceptional values. They are also designed to accept any of these values as valid operands and to propagate them as is shown below into the result.
The working precision can be changed or determined at anytime by invoking the procedure
PRECISION(dec_acc)
Description: Sets the working precision or inquires as to its current value in terms of equivalent significant decimal digits.
Class: Transformational function
Argument:
dec_acc shall be of type INTEGER
Result characteristics: the result shall be of type INTEGER
Result value: if dec_acc > 0, the number of digits to be retained, ndig, is set so that the working precision is greater than or equal to dec_acc. If dec_acc <=0, no change is made to the current working precision. In both cases the value returned is the current working precision defined as (ndig-1)*radd.
N.B. Since the leading digit may contain values less than 10 it may only represent a single decimal figure. Hence the ndig-1 in the above formular.
Examples: PRECISION(30) will set the working precision to at least 30D and with the parameters above will return the value 32 and ndig will be set to the value 5.
There are three functions designed to provide information about the detailed representation of a value and to manipulate a value by direct changes to the representation. These are:
EXPONENT(val)
FRACTION(val)
SET_EXPONENT(val,ex)
These routines assume a standard floating point representation such that
val = rad**exp * f
where f is a pure fraction. That is
1/rad ≤ |f| <1
This means that
FRACTION(val) = f = NUMBER(val%sig(1:nx-ex+1))
EXPONENT(val) = 1-ex
EXPONENT(FRACTION(val))
= 0
SET_EXPONENT(FRACTION(val),EXPONENT(val))
= val
EXPONENT(val)
Description: Inquires as to the effective exponent of a type(NUMBER) value
Class: Generic elemental
Argument: val shall be of type(NUMBER)
Result characteristics: The result shall be of type INTEGER
Result value: The result is the effective exponent of the number value. If val is represented by the component array val%sig(ex:nx), EXPONENT(val) returns the value 1-ex
Examples: EXPONENT(NUM(10)) will produce the value one
FRACTION(val)
Description: Inquires as to the effective pure fraction mantissa of a type(NUMBER) value
Class: Generic elemental
Argument: val shall be of type(NUMBER)
Result characteristics: The result shall be of type(NUMBER)
Result value: The result is the effective fraction mantissa of the number value. If val is represented by the component array val%sig(ex:nx), FRACTION(val) has a component array val%sig(1:nx-ex+1)
Examples: FRACTION(NUM(10)) will produce the NUMBER value equal to 10**(-7)=10/rad
SET_EXPONENT(val,ex)
Description: Sets the effective exponent of a type(NUMBER) value
Class: Generic elemental
Argument:
val shall be of type(NUMBER)
ex shall be of type INTEGER
Result characteristics: The result shall be of type(NUMBER)
Result value: The result has the same mantissa as val but with the effective exponent set to ex
Examples: SET_EXPONENT(NUM(10),2) will produce the NUMBER value equivalent to 10*10**rad
There are procedures for converting between INTEGER and NUMBER, and between CHARACTER and NUMBER.
NUM(val)
Description: Converts the value represented by its argument to the equivalent representation as a NUMBER
Class: Generic elemental
Argument:
val shall be of type INTEGER or CHARACTER In the case of a CHARACTER value the character string must denote a decimal value with the following format possibly with leading or trailing blanks
sdddd.ddddEsdddd or sdddd.dddd
where s denotes +,-, or nothing
dddd denotes a string of one or more decimal digits
Result characteristics: The result shall be of type NUMBER
Result value: In both cases the result is the equivalent value to that of the argument represented as a NUMBER. The number of digits in the return value is the minimum number required to exactly represent the value. If a string argument fails to denote a correctly formatted value, an ind result is returned. If it denotes a value that is too big or too small to be represented as a valid NUMBER, an overflow or an underflow value is returned.
Examples: NUM(10) will produce the value ten as a NUMBER. NUM("-1.0E+1") will produce the value -ten as a NUMBER.
INT(val)
Description: Converts the value represented by its argument to the equivalent representation as an INTEGER
Class: Generic transformational
Argument:
Val shall be of type NUMBER
Result characteristics: The result shall be of type INTEGER
Result value: The result the equivalent value to that of the argument represented as a INTEGER. If the argument denotes a value that is too big to represent as a valid INTEGER a fault is reported and execution is terminated.
Examples: INT(NUM(10)) will produce the value 10.
CHAR(val)
Description: Converts the value represented by its argument to a CHARACTER string representing the value as a standard floating point decimal.
Class: Generic transformational
Argument: Val shall be of type NUMBER
Result characteristics: The result shall be of type CHARACTER
Result value: The result is a CHARACTER string representing the equivalent value to that of the argument in a format:
^^si.ddddEsdddd
where ^^ represents zero or more blanks
s is the sign, -,or +
i is exactly one digit
dddd is one or more digits
Examples: CHAR(NUM(10)) will produce the value string " +1.0000E+1"
EFCHAR(val,w,d)
Description: Converts the value represented by its first argument to a CHARACTER string representing the value as a standard floating point decimal correctly truncated to 1PEw.d format.
Class: Generic transformational
Argument:
val shall be of type NUMBER
w,d shall be of type INTEGER
Result characteristics: The result shall be of type CHARACTER
Result value: The result is a CHARACTER string representing the equivalent value to that of the argument, val, in a format equivalent to 1PEw.d. This function is provided to enable formatted output.
Examples: EFCHAR(NUM(10),9,2) will produce the value string " +1.00E+1"
FFCHAR(val,w,d)
Description: Converts the value represented by its first argument to a CHARACTER string representing the value as a standard floating point decimal correctly truncated to Fw.d format.
Class: Generic transformational
Argument:
val shall be of type NUMBER
w,d shall be of type INTEGER
Result characteristics: The result shall be of type CHARACTER
Result value: The result is a CHARACTER string representing the equivalent value to that of the argument, val, in a format equivalent to Fw.d. This function is provided to enable formatted output.
Examples: FFCHAR(NUM(10),9,2) will produce the value string " +10.00"
The basic operations of arithmetic (+,-,*,/) are provided for NUMBER arguments and producing NUMBER results. The operation of raising a NUMBER to an INTEGER power (**) is also provided. All five operations are defined elementally for conformant array arguments.
If an exact result is possible within the current precision, the result will be exact and only the significant digits returned. Otherwise a result properly truncated to the current precision is returned.
The algorithms for both addition and subtraction employ a register that has two guard digits. The basic algorithm is the same for both operations; subtraction simply being addition with the sign of the digits for the second operand inverted. For normalised operands the only exceptional results that can occur are overflow, underflow, or exact cancellation to zero. The operations are defined to propagate exceptional value operands as shown in the following table.
Exceptional value propagation by addition and subtraction operation
|
A+B |
-unk |
-ovf |
-num |
-unf |
zero |
+unf |
+num |
+ovf |
+unk |
ind |
|
-unk |
-unk |
-ovf |
-unk |
-unk |
-unk |
ind |
ind |
ind |
ind |
ind |
|
-ovf |
-ovf |
-ovf |
-ovf |
-ovf |
-ovf |
-ovf |
-ovf |
ind |
ind |
ind |
|
-num |
-unk |
-ovf |
ALG |
-num |
-num |
-num |
ALG |
+ovf |
ind |
ind |
|
-unf |
-unk |
-ovf |
-num |
-unf |
-unf |
zero |
+num |
+ovf |
ind |
ind |
|
zero |
-unk |
-ovf |
-num |
-unf |
zero |
+unf |
+num |
+ovf |
+unk |
ind |
|
+unf |
ind |
-ovf |
-num |
zero |
+unf |
+unf |
+num |
+ovf |
+unk |
ind |
|
+num |
ind |
-ovf |
ALG |
+num |
+num |
+num |
ALG |
+ovf |
+unk |
ind |
|
+ovf |
ind |
ind |
+ovf |
+ovf |
+ovf |
+ovf |
+ovf |
+ovf |
+ovf |
ind |
|
+unk |
ind |
ind |
ind |
ind |
+unk |
+unk |
+unk |
+ovf |
+unk |
ind |
|
ind |
ind |
ind |
ind |
ind |
ind |
ind |
ind |
ind |
ind |
ind |
Where normalised values are represented by ±num and ALG represents the application of the basic algorithm.
The cost of these operations increases linearly with precision.
Multiplication is done by a straight forward school-book digit by digit multiply and accumulate algorithm, with partial normalisation of digits done as part of the running calculation. The potential integer overflow in the digit*digit calculation is avoided by decomposing each digit modulo rtrad and by performing the multiply, accumulate and carry modulo rad. An exponent fault will occur if an attempt is made to produce an exponent greater than rad in absolute value. Such cases will result in an underflow or overflow value being returned. The operation is defined to propagate exceptional value operands as shown in the following table.
Exceptional value propagation by
multiplication operation
|
A*B |
-unk |
-ovf |
-num |
-unf |
Zero |
+unf |
+num |
+ovf |
+unk |
ind |
|
-unk |
+unk |
+unk |
+unk |
+unk |
Ind |
-unk |
-unk |
-unk |
-unk |
ind |
|
-ovf |
+unk |
+ovf |
+ovf |
+unk |
Zero |
-unk |
-ovf |
-ovf |
-unk |
ind |
|
-num |
+unk |
+ovf |
ALG |
+unf |
Zero |
-unf |
ALG |
-ovf |
-unk |
ind |
|
-unf |
+unk |
+unk |
+unf |
+unf |
Zero |
-unf |
-unf |
-unk |
-unk |
ind |
|
zero |
ind |
zero |
zero |
zero |
Zero |
zero |
zero |
zero |
ind |
ind |
|
+unf |
-unk |
-unk |
-unf |
-unf |
Zero |
+unf |
+unf |
+unk |
+unk |
ind |
|
+num |
-unk |
-ovf |
ALG |
-unf |
Zero |
+unf |
ALG |
+ovf |
+unk |
ind |
|
+ovf |
-unk |
-ovf |
-ovf |
-unk |
Zero |
+unk |
+ovf |
+ovf |
+unk |
ind |
|
+unk |
-unk |
-unk |
-unk |
-unk |
Ind |
+unk |
+unk |
+unk |
+unk |
ind |
|
ind |
ind |
ind |
ind |
ind |
Ind |
ind |
ind |
ind |
ind |
ind |
The cost of multiplication using this algorithm increases quadratically with precision. The true dependence is on the product of the lengths, na*nb. The algorithm automatically adjusts for operands that can be represented with fewer than ndig digits. In particular, the important special case where one of the operands is a simple integer automatically has a linear dependence of the precision of the full-length operand. For this reason no special overload for the multiplication of a NUMBER by an integer is provided.
Division employs a variation on the school-book long division algorithm. Real arithmetic is used to determine a value for the next quotient digit. The dividend is updated by multiplication of the divisor by this and subtracting. This process is done by the same algorithm as used for the multiply and accumulation in the multiplication algorithm. An exponent fault will occur if an attempt is made to produce an exponent greater than rad in absolute value. In this case underflow or overflow values will be returned. Divide by zero will be handled by returning an indeterminant value. The operation is defined to propagate exceptional value operands as shown in the following table.
Exceptional
value propagation by division operation
|
A/B |
-unk |
-ovf |
-num |
-unf |
zero |
+unf |
+num |
+ovf |
+unk |
ind |
|
-unk |
+unk |
+unk |
+unk |
+unk |
ind |
-unk |
-unk |
-unk |
-unk |
ind |
|
-ovf |
+unk |
+unk |
+ovf |
+ovf |
ind |
-ovf |
-ovf |
-unk |
-unk |
ind |
|
-num |
+unk |
+unf |
ALG |
+ovf |
ind |
-ovf |
ALG |
-unf |
-unk |
ind |
|
-unf |
+unk |
+unf |
+unf |
+unk |
ind |
-unk |
-unf |
-unf |
-unk |
ind |
|
zero |
zero |
zero |
zero |
zero |
ind |
zero |
zero |
zero |
zero |
zero |
|
+unf |
-unk |
-unf |
-unf |
-unk |
ind |
+unk |
+unf |
+unf |
+unk |
ind |
|
+num |
-unk |
-unf |
ALG |
-ovf |
ind |
+ovf |
ALG |
+unf |
+unk |
ind |
|
+ovf |
-unk |
-unk |
-ovf |
-ovf |
ind |
+ovf |
+ovf |
+unk |
+unk |
ind |
|
+unk |
-unk |
-unk |
-unk |
-unk |
ind |
+unk |
+unk |
+unk |
+unk |
ind |
|
ind |
ind |
ind |
ind |
ind |
ind |
ind |
ind |
ind |
ind |
ind |
The cost of division increases quadratically with precision. The true dependence is on the product of the lengths, na*nb. The algorithm automatically adjusts for operands that can be represented with fewer than ndig digits. In particular, the important special case where the divisor is a simple integer automatically has a linear dependence of the precision of the full-length operand. For this reason no special overload for the division of a NUMBER by an integer is provided.
The operation (val**n) is provided where a NUMBER value is raised to an INTEGER power. An algorithm is used based on repeated squaring of val and multiplying the value into the result if the corresponding bit is set in the binary representation of ABS(n). If n is positive this gives the final result with a near minimum number of multiplications. If n is negative the final result is produced by dividing NUM(1) by the positive power. This operation may cause overflow or underflow. Also raising a zero value to a negative power returns an indeterminant value. The propagation of the exception values by this operation is shown in the following table. Note, the different propagation for odd and even powers.
Exceptional
value propagation by power operation
|
A**N |
-2n |
-2n-1 |
0 |
+2n+1 |
2n |
|
-unk |
+unk |
-unk |
+1.0 |
-unk |
+unk |
|
-ovf |
+unf |
-unf |
+1.0 |
-ovf |
+ovf |
|
-num |
ALG |
ALG |
+1.0 |
ALG |
ALG |
|
-unf |
+ovf |
-ovf |
+1.0 |
-unf |
+unf |
|
zero |
ind |
ind |
+1.0 |
zero |
zero |
|
+unf |
+ovf |
+ovf |
+1.0 |
+unf |
+unf |
|
+num |
ALG |
ALG |
+1.0 |
ALG |
ALG |
|
+ovf |
+unf |
+unf |
+1.0 |
+ovf |
+ovf |
|
+unk |
+unk |
+unk |
+1.0 |
+unk |
+unk |
|
ind |
ind |
ind |
+1.0 |
ind |
ind |
The relational operations (==,/=,<,<=,>=,>) are provided for NUMBER arguments producing LOGICAL results. The algorithms used do not rely on subtraction of the arguments and there is no danger of arithmetic errors being caused by these comparisons. Since there are only two possible results of type LOGICAL there is no available representation for situations where it not strictly possible to determine a true or false result. There is no representation for the, in principle, unknown result of comparing two unknown (unk) NUMBER values. Therefore to enable elemental extension of these operators, purely conventional true/false values are defined for such comparisons. These definitions are shown in the following tables.
Exceptional
value comparison by relational operation ==
|
A==B |
-unk |
-ovf |
-num |
-unf |
zero |
+unf |
+num |
+ovf |
+unk |
ind |
|
-unk |
TRUE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
|
-ovf |
FALSE |
TRUE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
|
-num |
FALSE |
FALSE |
ALG |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
|
-unf |
FALSE |
FALSE |
FALSE |
TRUE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
|
zero |
FALSE |
FALSE |
FALSE |
FALSE |
TRUE |
FALSE |
FALSE |
FALSE |
FALSE |
TRUE |
|
+unf |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
TRUE |
FALSE |
FALSE |
FALSE |
FALSE |
|
+num |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
ALG |
FALSE |
FALSE |
FALSE |
|
+ovf |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
TRUE |
FALSE |
FALSE |
|
+unk |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
TRUE |
FALSE |
|
ind |
FALSE |
FALSE |
FALSE |
FALSE |
TRUE |
FALSE |
FALSE |
FALSE |
FALSE |
TRUE |
Exceptional
value comparison by relational operation /=
|
A/=B |
-unk |
-ovf |
-num |
-unf |
zero |
+unf |
+num |
+ovf |
+unk |
ind |
|
-unk |
FALSE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
|
-ovf |
TRUE |
FALSE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
|
-num |
TRUE |
TRUE |
ALG |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
|
-unf |
TRUE |
TRUE |
TRUE |
FALSE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
|
zero |
TRUE |
TRUE |
TRUE |
TRUE |
FALSE |
TRUE |
TRUE |
TRUE |
TRUE |
FALSE |
|
+unf |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
FALSE |
TRUE |
TRUE |
TRUE |
TRUE |
|
+num |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
ALG |
TRUE |
TRUE |
TRUE |
|
+ovf |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
FALSE |
TRUE |
TRUE |
|
+unk |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
FALSE |
TRUE |
|
ind |
TRUE |
TRUE |
TRUE |
TRUE |
FALSE |
TRUE |
TRUE |
TRUE |
TRUE |
FALSE |
Exceptional
value comparison by relational operation <
|
A<B |
-unk |
-ovf |
-num |
-unf |
zero |
+unf |
+num |
+ovf |
+unk |
ind |
|
-unk |
FALSE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
|
-ovf |
FALSE |
FALSE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
|
-num |
FALSE |
FALSE |
ALG |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
|
-unf |
FALSE |
FALSE |
FALSE |
FALSE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
|
zero |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
TRUE |
TRUE |
TRUE |
TRUE |
FALSE |
|
+unf |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
TRUE |
TRUE |
TRUE |
FALSE |
|
+num |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
ALG |
TRUE |
TRUE |
FALSE |
|
+ovf |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
TRUE |
FALSE |
|
+unk |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
|
ind |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
TRUE |
TRUE |
TRUE |
TRUE |
FALSE |
Exceptional
value comparison by relational operation <=
|
A<=B |
-unk |
-ovf |
-num |
-unf |
zero |
+unf |
+num |
+ovf |
+unk |
ind |
|
-unk |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
|
-ovf |
FALSE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
|
-num |
FALSE |
FALSE |
ALG |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
|
-unf |
FALSE |
FALSE |
FALSE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
|
zero |
FALSE |
FALSE |
FALSE |
FALSE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
|
+unf |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
TRUE |
TRUE |
TRUE |
TRUE |
FALSE |
|
+num |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
ALG |
TRUE |
TRUE |
FALSE |
|
+ovf |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
TRUE |
TRUE |
FALSE |
|
+unk |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
TRUE |
FALSE |
|
ind |
FALSE |
FALSE |
FALSE |
FALSE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
Exceptional
value comparison by relational operation >=
|
A>=B |
-unk |
-ovf |
-num |
-unf |
zero |
+unf |
+num |
+ovf |
+unk |
ind |
|
-unk |
TRUE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
|
-ovf |
TRUE |
TRUE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
|
-num |
TRUE |
TRUE |
ALG |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
|
-unf |
TRUE |
TRUE |
TRUE |
TRUE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
|
zero |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
FALSE |
FALSE |
FALSE |
FALSE |
TRUE |
|
+unf |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
FALSE |
FALSE |
FALSE |
TRUE |
|
+num |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
ALG |
FALSE |
FALSE |
TRUE |
|
+ovf |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
FALSE |
TRUE |
|
+unk |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
|
ind |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
FALSE |
FALSE |
FALSE |
FALSE |
TRUE |
Exceptional
value comparison by relational operation >
|
A>B |
-unk |
-ovf |
-num |
-unf |
zero |
+unf |
+num |
+ovf |
+unk |
ind |
|
-unk |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
|
-ovf |
TRUE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
|
-num |
TRUE |
TRUE |
ALG |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
|
-unf |
TRUE |
TRUE |
TRUE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
|
zero |
TRUE |
TRUE |
TRUE |
TRUE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
|
+unf |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
FALSE |
FALSE |
FALSE |
FALSE |
TRUE |
|
+num |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
ALG |
FALSE |
FALSE |
TRUE |
|
+ovf |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
FALSE |
FALSE |
TRUE |
|
+unk |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
TRUE |
FALSE |
TRUE |
|
ind |
TRUE |
TRUE |
TRUE |
TRUE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
FALSE |
ABS(A)
Description: Returns the absolute value of its argument.
Class: Generic elemental
Argument: A shall be of type NUMBER
Result characteristics: The result shall be of type NUMBER
Result value: The result is the same as A if A is positive. The result is –A if A is negative.
Examples: ABS(NUM(-10)) will produce the value NUM(10)
SIGN(A,B)
Description: Returns the absolute value A times the sign of B.
Class: Generic elemental
Arguments: A & B shall be of type NUMBER
Result characteristics: The result shall be of type NUMBER
Result value: If B>=0, the result is the same as ABS(A). If B<0, the result is –ABS(A).
Examples: SIGN(NUM(10),NUM(-1)) will produce the value NUM(-10)
SQRT(A)
Description: Returns the square root of A.
Class: Generic transformational
Argument: A shall be of type NUMBER
Result characteristics: The result shall be of type NUMBER
Result value: If A>=0, the result is the square root of A correct to the current precision. If A<0, there is no valid result and the function fails causing the program to terminate execution. SQRT(unf) returns unf, SQRT(ovf) returns ovf, SQRT(unk) returns unk, SQRT(ind) returns ind.
Examples: SQRT(NUM(9) will produce the value NUM(3)
The source code for the module VPA30A.F95 is available via this link.