Previous | Contents | Index |
As operations must be performed on operands of the same type, the following conversions are performed when operands do not match in nonarithmetic operations:
A warning message is issued about a conversion in a concatenation expression, except for picture to character.
The built-in conversion functions can take arguments that are either arithmetic or string expressions. They are often used to convert an operand to the type required in a certain context-for instance, to convert a bit string to an arithmetic value for use as an arithmetic operand.
For the purpose of these functions, and in a few other contexts, derived arithmetic attributes are also defined for bit- and character-string expressions:
PL/I uses these derived attributes to determine the precision of values returned by the conversion functions if no precision is specified in the functions' argument lists. Note that the value of a string argument must also be convertible to the result type; for instance, '1.333' is convertible to arithmetic, but 'XYZ' is not.
Table 6-6 indicates which built-in functions you should use for each conversion between an arithmetic and a nonarithmetic type. In addition, you can use the BINARY, DECIMAL, FIXED, and FLOAT built-in conversion functions to control conversions between two arithmetic types.
Conversion | Function |
---|---|
Arithmetic to bit | BIT |
Arithmetic to character | CHARACTER |
Arithmetic or character to fixed-point arithmetic | FIXED |
Bit to arithmetic | BINARY |
Bit to character | CHARACTER |
Character to bit | BIT |
Character to decimal | DECIMAL |
Character to float | FLOAT |
Arithmetic or character to binary | BINARY |
Character to fixed binary | DECODE |
Decimal integer to character | ENCODE |
Integer (non-negative) to character | BYTE |
During assignment, PL/I automatically converts the derived data type of an expression to the data type of a target, if necessary. In assignments, conversions are defined between the noncomputational types POINTER and OFFSET, and between any two computational types. However, a conversion during assignment results in an error if PL/I cannot perform it in a meaningful way. For example, you can assign the string '123.4' to a fixed decimal variable; you cannot, however, assign the string 'ABCD' to the same variable. Similarly, an assignment of an arithmetic type to a fixed variable results in the FIXEDOVERFLOW condition if integral digits are lost.
Although PL/I performs conversions in assignment statements, such conversions may represent programming errors and are in violation of the PL/I G subset standard. Therefore, the compiler issues a warning message that an implicit conversion is taking place. These messages do not terminate the compilation and may not indicate errors; they simply alert you to the fact that your program converts one data type to another in a way that may cause a problem when the program is run. You can prevent such warning messages in two ways:
DECLARE (A,B) FIXED DECIMAL (5,2); A = '123.45'; /* Warning message */ B = FIXED('123.45',5,2); /* No warning */ |
Both assignment statements assign the same value to their targets; however, the first statement causes a warning message from the compiler, while the second statement does not.
Expressions of any computational type can be assigned to arithmetic variables. The conversion rules for each source type are described in the following sections.
A source expression of any arithmetic type can be assigned to a target variable of any arithmetic type. Note the following qualifications:
In the following examples, the specified source values are converted to FIXED DECIMAL(4,1):
Source Value | Converted Value |
---|---|
25.505 | 25.5 |
-2.562 | -2.5 |
101 | 101.0 |
5365 | FIXEDOVERFLOW - value undefined |
Let p be the precision of the floating-point target. If the source value is an integer that can be represented exactly in p digits, then the source value is converted to floating-point binary with no loss of accuracy.
Otherwise, the source value is converted to floating-point binary with rounding to precision p. For example, the constant 479 will be converted to FLOAT BINARY(24) without loss of accuracy, while the constant 16777217, which cannot be represented exactly in 24 bits, will be rounded during conversion.
Conversions from FIXED BINARY to other data types follow the rules outlined below. Notice that these rules assume both precision and scale.
Precisions of the source and target are (p,q) and (p1,q1), respectively. The precision of the result is (p2,q2).
Target | Result |
---|---|
FIXED DECIMAL(p1,q1) | p2=1+CEIL(p1/3.32) and q2=CEIL(q1/3.32). |
FIXED BINARY(p1,q1) | Precision and scale of the source are maintained during conversion; therefore, padding or truncation can occur. If nonzero bits are lost on the left, the result is undefined. |
FLOAT DECIMAL(p1) | p2=CEIL(p1/3.32). The exponent indicates any fractional value. |
FLOAT BINARY(p1) | p2=p1. The mantissa indicates any fractional value. |
PICTURE | The target implies FIXED DECIMAL and is converted accordingly. |
CHARACTER | The binary precision (p,q) is converted to a FIXED DECIMAL with precision (p1,q1), where p1=1+CEIL(p/3.32) and q1=CEIL(q/3.32). Then the rules for conversion from FIXED DECIMAL to CHARACTER are in effect. |
BIT | The binary precision (p,q) is converted to an intermediate bit string where the size or precision is MIN(31,p-q). Then the intermediate bit string is converted to BIT(n). If (p-q) is negative or zero, the result is a null bit string. |
If the scale factor is negative, substitute the FLOOR value for CEIL in the above calculations which contain q's.
In PL/I all pictured values have the associated attributes FIXED DECIMAL(p,q), where p is the total number of characters in the picture specification that specify decimal digits, and q is the total number of these digits that occur to the right of the V character. If the picture specification does not include a V character, then q is zero. This value is assigned to the target, following the PL/I rules for arithmetic to arithmetic conversion.
When a bit-string value is assigned to an arithmetic variable, PL/I treats the bit string as a fixed-point binary value. A string of type BIT(n) is converted to FIXED BINARY(m,0), where m = min(n,31) .
If the converted value is greater than or equal to 2^{31} , then FIXEDOVERFLOW is signaled. The leftmost bit in the bit string (as output by PUT LIST) is the most significant bit in the fixed-point binary value, not its sign. If the bit string is null, the fixed-point binary value is zero.
The intermediate fixed-point binary value is then converted to the target arithmetic type.
Note that bit strings are stored internally with the leftmost bit in the lowest address. The conversion to an arithmetic type must reverse the bits from this representation; therefore, you should avoid this conversion when performance is a consideration.
CONVTB: PROCEDURE OPTIONS(MAIN); DECLARE STATUS FIXED BINARY(8); DECLARE STATUS_D FIXED DECIMAL(10); DECLARE OUT PRINT FILE; OPEN FILE(OUT) TITLE('CONVTB.OUT'); ON FIXEDOVERFLOW PUT SKIP FILE(OUT) LIST('Fixedoverflow:'); STATUS = '1001101'B; PUT SKIP FILE(OUT) LIST(STATUS); STATUS_D = '001101'B; PUT SKIP FILE(OUT) LIST(STATUS_D); STATUS = '1232'B2; PUT SKIP FILE(OUT) LIST(STATUS); STATUS = 'FF'B4; PUT SKIP FILE(OUT) LIST(STATUS); STATUS_D = '10111111111111111111111111111111'B; END CONVTB; |
Note that because the program CONVTB performs implicit conversions, the compiler issues WARNING messages. (Linking and running are accomplished successfully because the conversions are valid.)
The program CONVTB produces the following output:
77 13 110 255 Fixedoverflow: |
The leftmost bit of all the bit-string constants is treated as the most significant numeric bit, not as a sign. For instance, the hexadecimal constant <BIT_STRING>(FF)B4 is converted to 255 instead of -127. The last assignment to STATUS_D signals the FIXEDOVERFLOW condition because the bit-string constant, when represented as a binary integer, is greater than 2^{31} . The resulting value of STATUS_D is undefined.
When a character string is assigned to an arithmetic value, PL/I creates an intermediate numeric value based on the characters in the string. The type of this intermediate value is the same as that of an ordinary arithmetic constant comprising the same characters; for example, 342.122E-12 and <BIT_STRING>(342.122E-12) are both floating-point decimal.
The character string can contain any series of characters that describes a valid arithmetic constant. That is, the character string can contain any of the numeric digits 0 through 9, a plus (+) or minus (-) sign, a decimal point (.), and the letter E. If the character string contains any invalid characters, the CONVERSION condition is signaled. See the following examples.
If the implied data type of the character string does not match the data type of the arithmetic target, PL/I converts the intermediate value to the data type of the target, following the PL/I rules for arithmetic to arithmetic conversions. In conversions to fixed point, FIXEDOVERFLOW is signaled if the character string specifies too many integral digits. Excess fractional digits are truncated without signaling a condition.
If the source character string is null or contains all spaces, the resulting arithmetic value is zero.
DECLARE SPEED FIXED DECIMAL (9,4); SPEED = '23344.3882'; /* string converted to 23344.3882 */ SPEED = '32423.23SD'; /* CONVERSION condition */ SPEED = '4324324.3933'; /* FIXEDOVERFLOW condition */ SPEED = '1.33336'; /* string converted to 1.3333 */ |
In the conversion of any data type to a bit string, PL/I first converts the source data item to an intermediate bit-string value. Then, based on the length of the target string, it does the following:
The next sections describe how PL/I arrives at the intermediate bit-string value for each data type.
In converting an arithmetic value sv to a bit-string value, PL/I performs the following steps:
Source | Precision p |
---|---|
FIXED BINARY(r,s) | min(31,r-s) |
FLOAT BINARY(r) | min(31,r) |
FIXED DECIMAL(r,s) | min(31,ceil((r-s)*3.32)) |
FLOAT DECIMAL(r) | min(31,ceil(r*3.32)) |
Bit strings are stored internally with the leftmost bit in the lowest address. The conversion must reverse the bits from this representation and should therefore be avoided when performance is a consideration. Note also that during the conversion, the sign of the arithmetic value and any fractional digits are lost.
CONVB: PROCEDURE OPTIONS(MAIN); DECLARE NEW_STRING BIT(10); DECLARE LONGSTRING BIT(16); DECLARE OUT PRINT FILE; OPEN FILE(OUT) TITLE('CONVB1.OUT'); NEW_STRING = 35; PUT FILE(OUT) SKIP LIST('35 converted to BIT(10):',NEW_STRING); NEW_STRING = -35; PUT FILE(OUT) SKIP LIST('-35 converted to BIT(10):',NEW_STRING); NEW_STRING = 23.12; PUT FILE(OUT) SKIP LIST('23.12 converted to BIT(10):',NEW_STRING); NEW_STRING = .2312; PUT FILE(OUT) SKIP LIST('.2312 converted to BIT(10):',NEW_STRING); NEW_STRING = 8001; PUT FILE(OUT) SKIP LIST('8001 converted to BIT(10):',NEW_STRING); LONGSTRING = 8001; PUT FILE(OUT) SKIP LIST('8001 converted to BIT(16):',LONGSTRING); END CONVB; |
Note that because the program CONVB performs implicit conversions, the compiler issues WARNING messages. (Linking and running are accomplished successfully because the conversions are valid.)
The program CONVB produces the following output:
35 converted to BIT(10): '0100011000'B -35 converted to BIT(10): '0100011000'B 23.12 converted to BIT(10): '0010111000'B .2312 converted to BIT(10): '0000000000'B 8001 converted to BIT(10): '0111110100'B 8001 converted to BIT(16): '0111110100000100'B |
The values 35 and -35 produce the same bit string because the sign is lost in the conversion. In the first assignment, 35, which is FIXED DECIMAL(2,0), is converted to FIXED BINARY(7,0) and then to a 7-bit string (<BIT_STRING>(0100011)B). Three additional bits are appended to this intermediate bit string when it is assigned to NEW_STRING. Notice that the low-order bit of 8001 is lost when the constant is assigned to a BIT(10) variable.
If the source value is pictured, its associated fixed-point decimal value is extracted. The fixed-point decimal value is then converted to a bit string, following the previous rules for arithmetic to bit-string conversion.
PL/I can convert a character string of 0s and 1s to a bit string. Any character in the character string other than 0 or 1, including spaces, will signal the CONVERSION condition.
PL/I converts each 0 or 1 character in the character string to a 0 or a 1 bit in the corresponding position (as represented by PUT LIST) in the intermediate bit string.
If the source is a null character string, the intermediate string is a null bit string.
DECLARE NEW_STRING BIT(4); NEW_STRING = '0010'; /* NEW_STRING = '0010'B */ NEW_STRING = '11'; /* NEW_STRING = '1100'B */ NEW_STRING = 'AS110'; /* CONVERSION condition */ |
In the conversion of any data type to a character string, PL/I first converts the source value to an intermediate character-string value. Then it does one of the following:
The rules for how PL/I arrives at the intermediate string for conversion of each data type are described below. Examples illustrate the intermediate value as well as the resulting value.
The manner in which PL/I converts an arithmetic data item depends on the data type of the item, as described below.
If the data item source value is of type FIXED BINARY(p1,q1), PL/I first converts it to type FIXED DECIMAL(p2,q2), where:
p2 = min(ceil(p1/3.32)+1,31)
q2 = max(0,min(ceil(q1/3.32),31))
PL/I converts a value with attributes FIXED DECIMAL(p,q) to an intermediate string of length p+3. The numeric value is right-justified in the string. If the value is negative, a minus sign immediately precedes the value. If q is greater than zero, the value contains a decimal point followed by q digits. When p equals q, a 0 character precedes the decimal point. When q equals zero, a value of zero is represented by the 0 character.
Alternatively, the format of the intermediate string can be described by picture specifications, as follows:
'BB(p)-9' |
'-9V.(q)9' |
'B(p-q)-9V.(q)9' |
DECLARE STRING_1 CHARACTER (8), STRING_2 CHARACTER (4); STRING_1 = 283472.; /* intermediate string = ' 283472', STRING_1 = ' 28347' */ STRING_2 = 283472.; /* intermediate string = ' 283472', STRING_2 = ' 2' */ STRING_2 = -283472.; /* intermediate string = ' -283472', STRING_2 = ' -2' */ STRING_2 = -.003344; /* intermediate string = '-0.003344', STRING_2 = '-0.0' */ STRING_2 = -283.472; /* intermediate string = ' -283.472', STRING_2 = ' -28' */ STRING_2 = 283.472; /* intermediate string = ' 283.472', STRING_2 = ' 28' */ |
Previous | Next | Contents | Index |