PL/I was originally introduced for the IBM 360 in the mid 1960's. As far as I

know all subsequent IBM main frames (370, 390 as well as other lines such as

the 4300 series) all have the same data formats. If I am mistaken on this I

hope someone will correct me.

PL/I has so called coded arithmetic and numeric character numeric data types

that may be used to represent numeric values. There is also character and bit

data of course.

The coded arithmetic types include FIXED DECIMAL, FIXED BINARY, FLOAT DECIMAL

and FLOAT BINARY. (Coded arithmetic types have base, scale, mode, and

precision. I will ignore complex mode since complex simply consists or a pair

of reals. Be aware however that the possibility that the operands might be

complex is the reason for the seemingly unnecessary +1 in the formulas for the

precision of many intermediate results.) FIXED DECIMAL and FIXED BINARY have

distinct (and dramatically different) internal representations. In contrast

there is only one internal floating point (real) representation which is most

aptly described as float hexadecimal. Both FLOAT DECIMAL and FLOAT BINARY are

mapped onto this.

The original 360 supported two sizes of binary integers: 16 bit and 32 bit.

The hardware supported both signed and unsigned representations, but PL/I only

supported signed numbers. A FIXED BINARY number of precision (p,q) was mapped

onto a 16 bit 2's complement integer if p<=15 and onto a 32 bit 2's complement

integer if 16<=p<=31. Precision >31 was not supported. The mainframe

computers all use "big endian" representation. In other words the most

significant bit of the number is the leftmost bit of the first (lowest

addressed) byte and the least significant bit is the rightmost bit of the last

(highest addressed) byte. If the most significant bit is a '1'b the number is

negative; otherwise, it is positive or zero. More recent implementations of

PL/I (at least on micro computers such as PC's) support unsigned FIXED BINARY

values as well and also map numbers with precision <=8 onto a single byte.

Some if not all of the micro computer implementations use "little endian"

representation in which the bytes of a multi-byte binary value are stored in

the opposite order. In other words, the most significant bit is the leftmost

bit of the last (highest addressed) byte; and the least significant bit is the

rightmost bit of the first (lowest addressed) byte.

If a FIXED BINARY number has a non zero scale factor (q) it is treated as

follows:

If q>0 the q least significant bits of the value are considered as fractional

digits. Note that it is possible for q to be greater than p. In this case

there are q-p implied significant fractional copies of the most significant bit

to the left of the most significant bit for signed numbers and q-p zeros for

unsigned numbers.

If q<0 there are |q| implied zeros between the least significant bit and the

radix point.

I have not had access to a mainframe system since 1990 so I am unaware of any

extensions that have been added since then. It would not surprise me to learn

that the maximum precision had been extended to 64 bits but I do not know

whether or not this has happened.

FIXED DECIMAL numbers always have an odd number of decimal digits in their

internal representation. If p is even there is an extra high order zero.

Each stored in a 4-bit "nibble". The right most "nibble" of the least

significant byte is used to represent the sign of the number.

(FIXED DECIMAL numbers use sign-magnitude rather than complement

representation.) the digits 0-9 are represented by the encodings 0000-1001.

In the sign position, 1010(A), 1100(C), 1110(E), and 1111(F) are treated as

plus and 1011(B) and 1101(D) are treated as minus. Note that there are six

representations of zero, four representations of each positive value and two

representations of each negative value. In addition there are many bit

patterns that do not represent valid values and will cause a data exception if

an arithmetic operation is attempted on them.

The maximum value of p supported by the original implementations is 15. I

believe that the latest versions of the mainframe compiler may have increased

this limit to 31 but I am not certain of this.

The scale factor (q) is treated analogously to the binary case except that it

is measured in decimal rather than binary digits.

For all fixed point data types, the p significant digits specified by the

precision attribute are stored in the least significant p digits of the actual

internal representation. Any extra high order digits participate in all

arithmetic operations. If non-trivial values make their way into these digit

positions which exist but are not part of the declared precision of the value

this will be detected only if the SIZE condition is enabled. Enabling SIZE

entails extra execution time overhead.

The last time I looked the IBM mainframe line had three sizes of floating point

representation: single, double, and extended. As far as I know this is still

the case.

Single precision floating point values are stored in a 32 bit word.

bit 0 is the sign 0=+, 1=-

bits 1-7 are the exponent of 16 in "excess 64 notation".

What this means is that the seven bit value which could represent an integer

between 0 and 127 inclusive is interpreted as 64 less than its apparent value.

In other words 0 means -64, 1 means -63, ..., 64 means 0, 65 means 1, ... 127

means 63.

bits 8-31 are a 6 digit hexadecimal fraction. What this means is that bits

8-11 represent the first hexadecimal fractional digit, bits 12-15, the second,

... and bits 28-31 the sixth.

Call the value of the sign bit s; the value of the exponent field e'; and the

value of the fraction f.

Let e=e'-64. Then the value represented by the floating point number is

((-1)**s)*f*16**e

Double precision floating point values are stored in a 64 bit double word.

The format is identical to the single precision format except for the fact that

the fractional part consists of 14 hexadecimal digits in bits 8-63.

Extended precision floating point values consist of two consecutive double

precision values in which the least significant (rightmost) value has an

exponent that is 14 less than the most significant part. (If the exponent

field of the left most part is 13 or less the apparent value of the right most

exponent field is 128 too large but the hardware is able to deal with this

correctly.)

For floating point data precision is specified by p. Floating point data are

mapped onto the available representations as follows:

DECIMAL BINARY

Single or Short <=6 <=21

Double or Long (7,16) (22,53)

Extended >16 >53

No attempt is made to map the precision more precisely than this.

Note that for the workstation (PC) versions of PL/I there is a compiler option

to choose between emulating the mainframe floating point representation or

using the native IEEE representation.

Numeric character data is described by a picture specification that does not

include the picture characters A of X. The alternative is pictured character

data which may only include the picture characters A, X, and 9.

The numeric character picture not only specifies how many decimal digits of

numeric data there are and where the decimal point is to be assumed to be

located, but may also specify how the value is to appear when displayed.

Only the digits and sign are actually stored and they take one byte each. On

mainframe implementations the EBCDIC encoding is used to store the digits. On

workstations, either ASCII or EBCDIC may be used depending on a compiler

option. (Later mainframe compilers may well support ASCII also but I do not

know this for a fact.) In EBCDIC the digits 0-9 have the encodings

X'F0'-X'F9'. In ASCII the encodings are X'30'-X'39'. I am uncertain as to

what encodings are used for the sign but a simple experiment using UNSPEC will

suffice to find out.