Kednos PL/I for OpenVMS Systems
Reference Manual


Previous Contents Index

6.4.3 Conversion of Operands in Nonarithmetic Operations

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.

6.4.4 Built-In Conversion Functions

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.

Table 6-6 Built-In Functions for Conversions Between Arithmetic and Nonarithmetic 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

6.4.5 Implicit Conversion During Assignment

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:

For example:


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.

6.4.6 Assignment to Arithmetic Variables

Expressions of any computational type can be assigned to arithmetic variables. The conversion rules for each source type are described in the following sections.

6.4.6.1 Arithmetic to Arithmetic Conversions

A source expression of any arithmetic type can be assigned to a target variable of any arithmetic type. Note the following qualifications:

6.4.6.1.1 Conversions to Fixed Point

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

6.4.6.1.2 Conversions to Floating Point

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.

6.4.6.1.3 Conversions from FIXED BINARY to Other Data Types

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.

6.4.6.2 Pictured to Arithmetic Conversions

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.

6.4.6.3 Bit-String to Arithmetic Conversions

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 231 , 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.

Examples


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 231 . The resulting value of STATUS_D is undefined.

6.4.6.4 Character-String to Arithmetic Conversions

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.

Examples


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 */ 

6.4.7 Assignments to Bit-String Variables

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.

6.4.7.1 Arithmetic to Bit-String Assignments

In converting an arithmetic value sv to a bit-string value, PL/I performs the following steps:

  1. Let v = abs(sv) .
  2. Determine a precision p as follows:
    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))
  3. If p=0 (for example, when r=s), the intermediate string is a null bit string. Otherwise, the value v is converted to an integer n of type FIXED BINARY(p,0). If n>=2p , the FIXEDOVERFLOW condition is signaled; otherwise, the intermediate bit string is of length p, and each of its bits represents a binary digit of n.

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.

Examples


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.

6.4.7.2 Pictured to Bit-String Conversions

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.

6.4.7.3 Character-String to Bit-String Conversions

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.

Examples


DECLARE NEW_STRING BIT(4); 
 
NEW_STRING = '0010'; 
      /* NEW_STRING = '0010'B */ 
 
NEW_STRING = '11'; 
      /* NEW_STRING = '1100'B */ 
 
NEW_STRING = 'AS110'; 
      /* CONVERSION condition */ 

6.4.8 Assignments to Character-String Variables

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.

6.4.8.1 Arithmetic to Character-String Conversions

The manner in which PL/I converts an arithmetic data item depends on the data type of the item, as described below.

6.4.8.1.1 Conversion from Fixed-Point Binary or Fixed-Point Decimal

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:

  1. If q=0, the intermediate string is the string created by the following picture specification:


    'BB(p)-9' 
    

    That is, the first two characters of the string are spaces. The last p characters in the string are the digit characters representing the integer; leading zeros are replaced by spaces except in the last position. If the integer is negative, a minus sign immediately precedes the first digit; if the number is not negative, this position contains a space. At least one digit always appears in the last position in the string.

  2. If p=q, the intermediate string is the string created by the following picture specification:


    '-9V.(q)9' 
    

    That is, the first three characters are (in order) an optional minus sign if the fraction is negative, the digit 0, and a decimal point. If the number is not negative, the first character is a space. The last q characters in the string are the fractional digits of the number.

  3. If p > q, the intermediate string is the string created by the following picture specification:


    'B(p-q)-9V.(q)9' 
    

    That is, the first character is always a space; the last q characters are the fractional digits of the number and are preceded by a decimal point; the decimal point is always preceded by at least one digit, which can be zero; all integral digits appear before the decimal point, and leading zeros are replaced by spaces; a minus sign precedes the first integral digit if the number is negative; if the number is not negative, then the minus sign is replaced by a space.

Examples


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