
HP OpenVMS RTL General Purpose (OTS$) Manual
This PL/I example translates a hexadecimal value in ASCII into a fixed
binary value. This program continues to prompt for input values until
the user presses Ctrl/Z.
One sample of the output generated by this program is as follows:
$ RUN HEX
Hex value: 1A
1A Hex equals 26 Decimal
Hex value: C
C Hex equals 12 Decimal
Hex value: Ctrl/Z

OTS$DIVCx
The Complex Division routines return a complex result of a division on
complex numbers.
Format
OTS$DIVC complexdividend ,complexdivisor
OTS$DIVCD_R3 complexdividend ,complexdivisor (VAX only)
OTS$DIVCG_R3 complexdividend ,complexdivisor
OTS$DIVCS complexdividend ,complexdivisor
OTS$DIVCT_R3 complexdividend ,complexdivisor
Each of these formats corresponds to one of the floatingpoint complex
types.
RETURNS
OpenVMS usage: 
complex_number 
type: 
F_floating complex, D_floating complex, G_floating complex,
IEEE S_floating complex, IEEE T_floating complex, 
access: 
write only 
mechanism: 
by value 
Complex result of complex division. OTS$DIVC returns an Ffloating
complex number. OTS$DIVCD_R3 returns a Dfloating complex number.
OTS$DIVCG_R3 returns a Gfloating complex number. OST$DIVCS returns an
IEEE Sfloating complex number. OTS$DIVCT_R3 returns an IEEE Tfloating
complex number.
Arguments
complexdividend
OpenVMS usage: 
complex_number 
type: 
F_floating complex, D_floating complex, G_floating complex,
IEEE S_floating complex, IEEE T_floating complex 
access: 
read only 
mechanism: 
by value 
Complex dividend. The complexdividend argument
contains a floatingpoint complex value. For OTS$DIVC,
complexdividend is an Ffloating complex number. For
OTS$DIVCD_R3, complexdividend is a Dfloating complex
number. For OTS$DIVCG_R3, complexdividend is a
Gfloating complex number. For OTS$DIVCT_R3,
complexdividend is an IEEE Tfloating complex number.
complexdivisor
OpenVMS usage: 
complex_number 
type: 
F_floating complex, D_floating complex, G_floating complex,
IEEE S_floating complex, IEEE T_floating complex 
access: 
read only 
mechanism: 
by value 
Complex divisor. The complexdivisor argument contains
the value of the divisor. For OTS$DIVC,
complexdivisor is an Ffloating complex number. For
OTS$DIVCD_R3, complexdivisor is a Dfloating complex
number. For OTS$DIVCG_R3, complexdivisor is a
Gfloating complex number. For OTS$DIVCS,
complexdivisor is an IEEE Sfloating complex number.
For OTS$DIVCS, complexdividend is an IEEE Sfloating
complex number. For OTS$DIVCT_R3, complexdivisor is
an IEEE Tfloating complex number.
Description
These routines return a complex result of a division on complex numbers.
The complex result is computed as follows:
 Let (a,b) represent the complex dividend.
 Let (c,d) represent the complex divisor.
 Let (r,i) represent the complex quotient.
The results of this computation are as follows:
r = (ac + bd)/(c^{2} + d^{2})
i = (bc  ad)/(c^{2} + d^{2})

On Alpha and I64 systems, some restrictions apply when linking OTS$DIVC
or OTS$DIVCG_R3. See Chapter 1 for more information about these
restrictions.
Condition Values Signaled
SS$_FLTDIV_F

Arithmetic fault. Floatingpoint division by zero.

SS$_FLTOVF_F

Arithmetic fault. Floatingpoint overflow.

Examples
#1 
C+
C This Fortran example forms the complex
C quotient of two complex numbers using
C OTS$DIVC and the Fortran random number
C generator RAN.
C
C Declare Z1, Z2, Z_Q, and OTS$DIVC as complex values.
C OTS$DIVC will return the complex quotient of Z1 divided
C by Z2: Z_Q = OTS$DIVC( %VAL(REAL(Z1)), %VAL(AIMAG(Z1),
C %VAL(REAL(Z2)), %VAL(AIMAG(Z2))
C
COMPLEX Z1,Z2,Z_Q,OTS$DIVC
C+
C Generate a complex number.
C
Z1 = (8.0,4.0)
C+
C Generate another complex number.
C
Z2 = (1.0,1.0)
C+
C Compute the complex quotient of Z1/Z2.
C
Z_Q = OTS$DIVC( %VAL(REAL(Z1)), %VAL(AIMAG(Z1)), %VAL(REAL(Z2)),
+ %VAL(AIMAG(Z2)))
TYPE *, ' The complex quotient of',Z1,' divided by ',Z2,' is'
TYPE *, ' ',Z_Q
END

This Fortran program demonstrates how to call OTS$DIVC. The output
generated by this program is as follows:
The complex quotient of (8.000000,4.000000) divided by (1.000000,1.000000)
is (6.000000,2.000000)

#2 
C+
C This Fortran example forms the complex
C quotient of two complex numbers by using
C OTS$DIVCG_R3 and the Fortran random number
C generator RAN.
C
C Declare Z1, Z2, and Z_Q as complex values. OTS$DIVCG_R3
C will return the complex quotient of Z1 divided by Z2:
C Z_Q = Z1/Z2
C
COMPLEX*16 Z1,Z2,Z_Q
C+
C Generate a complex number.
C
Z1 = (8.0,4.0)
C+
C Generate another complex number.
C
Z2 = (1.0,1.0)
C+
C Compute the complex quotient of Z1/Z2.
C
Z_Q = Z1/Z2
TYPE *, ' The complex quotient of',Z1,' divided by ',Z2,' is'
TYPE *, ' ',Z_Q
END

This Fortran example uses the OTS$DIVCG_R3 entry point instead. Notice
the difference in the precision of the output generated:
The complex quotient of (8.000000000000000,4.000000000000000) divided by
(1.000000000000000,1.000000000000000) is
(6.000000000000000,2.000000000000000)

OTS$DIV_PK_LONG
The Packed Decimal Division with Long Divisor routine divides
fixedpoint decimal data, which is stored in packed decimal form, when
precision and scale requirements for the quotient call for multiple
precision division. The divisor must have a precision of 30 or 31
digits.
Format
OTS$DIV_PK_LONG packeddecimaldividend ,packeddecimaldivisor
,divisorprecision ,packeddecimalquotient ,quotientprecision
,precisiondata ,scaledata
RETURNS
OpenVMS usage: 
cond_value 
type: 
longword (unsigned) 
access: 
write only 
mechanism: 
by value 
Arguments
packeddecimaldividend
OpenVMS usage: 
varying_arg 
type: 
packed decimal string 
access: 
read only 
mechanism: 
by reference 
Dividend. The packeddecimaldividend argument is the
address of a packed decimal string that contains the shifted dividend.
Before being passed as input, the
packeddecimaldividend argument is always multiplied
by 10^{c}, where c is defined as follows:
c = 31  prec(packeddecimaldividend)

Multiplying packeddecimaldividend by
10^{c} makes packeddecimaldividend
a 31digit number.
packeddecimaldivisor
OpenVMS usage: 
varying_arg 
type: 
packed decimal string 
access: 
read only 
mechanism: 
by reference 
Divisor. The packeddecimaldivisor argument is the
address of a packed decimal string that contains the divisor.
divisorprecision
OpenVMS usage: 
word_signed 
type: 
word (signed) 
access: 
read only 
mechanism: 
by value 
Precision of the divisor. The divisorprecision
argument is a signed word that contains the precision of the divisor.
The highorder bits are filled with zeros.
packeddecimalquotient
OpenVMS usage: 
varying_arg 
type: 
packed decimal string 
access: 
write only 
mechanism: 
by reference 
Quotient. The packeddecimalquotient argument is the
address of the packed decimal string into which OTS$DIV_PK_LONG writes
the quotient.
quotientprecision
OpenVMS usage: 
word_signed 
type: 
word (signed) 
access: 
read only 
mechanism: 
by value 
Precision of the quotient. The quotientprecision
argument is a signed word that contains the precision of the quotient.
The highorder bits are filled with zeros.
precisiondata
OpenVMS usage: 
word_signed 
type: 
word (signed) 
access: 
read only 
mechanism: 
by value 
Additional digits of precision required. The
precisiondata argument is a signed word that contains
the value of the additional digits of precision required.
OTS$DIV_PK_LONG computes the precisiondata argument
as follows:
precisiondata = scale(packeddecimalquotient)
+ scale(packeddecimaldivisor)
 scale(packeddecimaldividend)
 31 + prec(packeddecimaldividend)

scaledata
OpenVMS usage: 
word_signed 
type: 
word (signed) 
access: 
read only 
mechanism: 
by value 
Scale factor of the decimal point. The scaledata
argument is a signed word that contains the scale data.
OTS$DIV_PK_LONG defines the scaledata argument as
follows:
scaledata = 31  prec(packeddecimaldivisor)

Description
On VAX systems, before using this routine, you should determine whether
it is best to use OTS$DIV_PK_LONG, OTS$DIV_PK_SHORT, or the VAX
instruction DIVP. To determine this, you must first calculate
b, where b is defined as follows:
b = scale(packeddecimalquotient)
+ scale(packeddecimaldivisor)
 scale(packeddecimaldividend)
+ prec(packeddecimaldividend)

If b is greater than 31, then OTS$DIV_PK_LONG can be used to
perform the division. If b is less than 31, you could use the
instruction DIVP instead.
When using this routine on an OpenVMS Alpha system, an I64 system, or
on an OpenVMS VAX system and you have determined that you cannot use
DIVP, you need to determine whether you should use OTS$DIV_PK_LONG or
OTS$DIV_PK_SHORT. To determine this, you must examine the value of
scaledata. If scaledata is less
than or equal to 1, then you should use OTS$DIV_PK_LONG. If
scaledata is greater than 1, you should use
OTS$DIV_PK_SHORT instead.
Condition Value Signaled
SS$_FLTDIV

Fatal error. Division by zero.

Example

1
OPTION &
TYPE = EXPLICIT
!+
! This program uses OTS$DIV_PK_LONG to perform packed decimal
! division.
!
!+
! DECLARATIONS
!
DECLARE DECIMAL (31, 2) NATIONAL_DEBT
DECLARE DECIMAL (30, 3) POPULATION
DECLARE DECIMAL (10, 5) PER_CAPITA_DEBT
EXTERNAL SUB OTS$DIV_PK_LONG (DECIMAL(31,2), DECIMAL (30, 3), &
WORD BY VALUE, DECIMAL(10, 5), WORD BY VALUE, WORD BY VALUE, &
WORD BY VALUE)
!+
! Prompt the user for the required input.
!
INPUT "Enter national debt: ";NATIONAL_DEBT
INPUT "Enter current population: ";POPULATION
!+
! Perform the division and print the result.
!
! scale(divd) = 2
! scale(divr) = 3
! scale(quot) = 5
!
! prec(divd) = 31
! prec(divr) = 30
! prec(quot) = 10
!
! precdata = scale(quot) + scale(divr)  scale(divd)  31 +
! prec(divd)
! precdata = 5 + 3  2  31 + 31
! precdata = 6
!
! b = scale(quot) + scale(divr)  scale(divd) + prec(divd)
! b = 5 + 3  2 + 31
! b = 37
!
! c = 31  prec(divd)
! c = 31  31
! c = 0
!
! scaledata = 31  prec(divr)
! scaledata = 31  30
! scaledata = 1
!
! b is greater than 31, so either OTS$DIV_PK_LONG or
! OTS$DIV_PK_SHORT may be used to perform the division.
! If b is less than or equal to 31, then the DIVP
! instruction may be used.
!
! scaledata is less than or equal to 1, so OTS$DIV_PK_LONG
! should be used instead of OTS$DIV_PK_SHORT.
!
!
CALL OTS$DIV_PK_LONG( NATIONAL_DEBT, POPULATION, '30'W, PER_CAPITA_DEBT, &
'10'W, '6'W, '1'W)
PRINT "The per capita debt is ";PER_CAPITA_DEBT
END

This BASIC example program uses OTS$DIV_PK_LONG to perform packed
decimal division. One example of the output generated by this program
is as follows:
$ RUN DEBT
Enter national debt: ? 12345678
Enter current population: ? 1212
The per capita debt is 10186.20297

OTS$DIV_PK_SHORT
The Packed Decimal Division with Short Divisor routine divides
fixedpoint decimal data when precision and scale requirements for the
quotient call for multipleprecision division.
Format
OTS$DIV_PK_SHORT packeddecimaldividend ,packeddecimaldivisor
,divisorprecision ,packeddecimalquotient ,quotientprecision
,precisiondata
RETURNS
OpenVMS usage: 
cond_value 
type: 
longword (unsigned) 
access: 
write only 
mechanism: 
by value 
Arguments
packeddecimaldividend
OpenVMS usage: 
varying_arg 
type: 
packed decimal string 
access: 
read only 
mechanism: 
by reference 
Dividend. The packeddecimaldividend argument is the
address of a packed decimal string that contains the shifted dividend.
Before being passed as input, the
packeddecimaldividend argument is always multiplied
by 10^{c}, where c is defined as follows:
c = 31  prec(packeddecimaldividend)

Multiplying packeddecimaldividend by
10^{c} makes packeddecimaldividend
a 31digit number.
packeddecimaldivisor
OpenVMS usage: 
varying_arg 
type: 
packed decimal string 
access: 
read only 
mechanism: 
by reference 
Divisor. The packeddecimaldivisor argument is the
address of a packed decimal string that contains the divisor.
divisorprecision
OpenVMS usage: 
word_signed 
type: 
word (signed) 
access: 
read only 
mechanism: 
by value 
Precision of the divisor. The divisorprecision
argument is a signed word integer that contains the precision of the
divisor; highorder bits are filled with zeros.
packeddecimalquotient
OpenVMS usage: 
varying_arg 
type: 
packed decimal string 
access: 
write only 
mechanism: 
by reference 
Quotient. The packeddecimalquotient argument is the
address of a packed decimal string into which OTS$DIV_PK_SHORT writes
the quotient.
quotientprecision
OpenVMS usage: 
word_signed 
type: 
word (signed) 
access: 
read only 
mechanism: 
by value 
Precision of the quotient. The quotientprecision
argument is a signed word that contains the precision of the quotient;
highorder bits are filled with zeros.
precisiondata
OpenVMS usage: 
word_signed 
type: 
word (signed) 
access: 
read only 
mechanism: 
by value 
Additional digits of precision required. The
precisiondata argument is a signed word that contains
the value of the additional digits of precision required.
OTS$DIV_PK_SHORT computes the precisiondata argument
as follows:
precisiondata = scale(packeddecimalquotient)
+ scale(packeddecimaldivisor)
 scale(packeddecimaldividend)
 31 + prec(packeddecimaldividend)

Description
On VAX systems, before using this routine, you should determine whether
it is best to use OTS$DIV_PK_LONG, OTS$DIV_PK_SHORT, or the VAX
instruction DIVP. To determine this, you must first calculate
b, where b is defined as follows:
b = scale(packeddecimalquotient) + scale(packeddecimaldivisor) 
scale(packeddecimaldividend) + prec(packeddecimaldividend)

If b is greater than 31, then OTS$DIV_PK_SHORT can be used to
perform the division. If b is less than 31, you could use the
VAX instruction DIVP instead.
When using this routine on an OpenVMS Alpha system, an I64 system, or
on an OpenVMS VAX system and you have determined that you cannot use
DIVP, you need to determine whether you should use OTS$DIV_PK_LONG or
OTS$DIV_PK_SHORT. To determine this, you must examine the value of
scaledata. If scaledata is less
than or equal to 1, then you should use OTS$DIV_PK_LONG. If
scaledata is greater than 1, you should use
OTS$DIV_PK_SHORT instead.
Condition Value Signaled
SS$_FLTDIV

Fatal error. Division by zero.

OTS$JUMP_TO_BPV (I64 Only)
The Jump to Bound Procedure Value routine transfers control to a bound
procedure.
Format
OTS$JUMP_TO_BPV boundfuncvalue ,standardargs ,...
RETURNS
None.
Arguments
boundfuncvalue
OpenVMS usage: 
quadword address 
type: 
address 
access: 
read only 
mechanism: 
by value in register R1 (GP) 
Function value for the procedure being called.
standardargs
Zero or more arguments to be passed to the called routine, passed using
standard conventions (including the AI register).
Description
When a procedure value that refers to a bound procedure descriptor is
used to make a call, the routine designated in the OTS_ENTRY field
(typically OTS$JUMP_TO_BPV) receives control with the GP register
pointing to the bound procedure descriptor (instead of a global offset
table). This routine performs the following steps:
 Load the "real" target entry address into a volatile branch
register, for example, B6.
 Load the dynamic environment value into the appropriate
upleveladdressing register for the target function, for example,
OTS$JUMP_TO_BPV uses R9.
 Load the "real" target GP address into the GP register
 Transfer control (branch, not call) to the target entry address.
Control arrives at the real target procedure address with both the GP
and environment register values established appropriately.
Support routine OTS$JUMP_TO_BPV is included as a standard library
routine. The operation of OTS$JUMP_TO_BPV is logically equivalent to
the following code:
OTS$JUMP_TO_BPV::
add gp=gp,24 ; Adjust GP to point to entry address
ld8 r9=[gp],16 ; Load target entry address
mov b6=r9
ld8 r9=[gp],8 ; Load target environment value
ld8 gp=[gp] ; Load target GP
br b6 ; Transfer to target

Note that there can be multiple OTS$JUMP_TO_BPVlike support routines,
corresponding to different target registers where the environment value
should be placed. The code that creates the bound function descriptor
is also necessarily compiled by the same compiler that compiles the
target procedure, thus can correctly select an appropriate support
routine.
Condition Values Returned
