The MOVE and MOVEL op codes are workhorses in fixed-format RPG, but they don't exist in free-format. Use the EVAL op code and a few BIFs to remove MOVE and MOVEL!
There are many uses for the MOVE and MOVEL operation codes: initializing (or even declaring) variables, moving values from one variable to another (which sometimes implies a conversion between data types—character to numeric or vice versa, for example), truncating a numeric value, copying part of a string to a different string variable, and so on. Providing you with the tools to totally remove MOVE from your code is a considerable task, and I'll try to address it in this and the following TechTips, thus paving the way to a migration to free-format (that too will be the subject of a few TechTips later in this series).
Removing MOVE from Your Numeric Conversion Operations
This time, I'll focus on the conversion to numeric data types. Take the example below:
D REGION S 2A Inz('12')
D REGCOD S 2P 0 Inz(*ZEROS)
(…)
C MOVEL REGION REGCOD
This is a fairly common use of MOVE: moving a character value into a decimal variable, implicitly forcing a data-type conversion from character to decimal. This works, no question about that. The problem is that the readability is not the best because the MOVEL operation hides the data types involved and might, in some cases, cause unexpected and (more importantly) undetected errors. By using EVAL and the %DEC BIF, as shown below, you can achieve the same result, in a more readable manner that simultaneously prepares the code for a smooth free-format conversion:
C EVAL REGCOD = %DEC(REGION)
You can add a MONITOR block around the EVAL to check for errors. I won't go into details about that now, but I promise I'll explain it in a future TechTip. Anyway, back to the matter at hand: %DEC can be used with additional parameters that define the precision and number of decimal places used for the conversion operation. These two parameters are optional. There's also another BIF, similar to %DEC, that automatically performs half-adjust; it's %DECH. However, this BIF requires all three parameters (numeric or character expression to convert, precision, and decimal places) to be specified. To help you understand the use of these BIFs and their parameters, here's an example adapted from IBM's ILE RPG Reference Manual:
D p7 s 7p 3 inz (1234.567)
D s9 s 9s 5 inz (73.73442)
D f8 s 8f inz (123.456789)
D c15a s 15a inz (' 123.456789 -')
D c15b s 15a inz (' + 9 , 8 7 6 ')
D result1 s 15p 5
D result2 s 15p 5
D result3 s 15p 5
* using numeric parameters
C EVAL result1 = %DEC(p7) + 0.011
* "result1" is now 1234.57800
C EVAL result2 = %DEC(s9 : 5: 0)
* "result2" is now 73.00000
C EVAL result3 = %DECH(f8: 5: 2)
* "result3" is now 123.46000
* using character parameters
C EVAL result1 = %DEC(c15a: 5: 2)
* "result1" is now -123.45
C EVAL result2 = %DECH(c15b: 5: 2)
* "result2" is now 9.88000
Have you noticed how the precision parameter in the second and third EVAL operations influences the final result? It's also important to mention that plus sign (+) or minus sign (-) characters will be used when converting a character string to a decimal value, as shown in the fourth EVAL operation. Please read the chapter on Conversion Operations in the ILE RPG Reference Manual for more details.
Need to Convert Something to Integer? Here's a (h)%int
What if the target data type was an integer or a float? Well, there are also BIFs for that: %INT and %FLOAT, respectively. Let's start with %INT: it has only one parameter—the character or numeric expression to be converted to integer—and it simply drops the decimal places when performing the conversion. In other words, 123.456 will be converted to 123. If you need to take into account the decimal part, performing the half-adjust, then you should use %INTH. It's similar to %INT in every way, except for the half-adjust operation. Here's an example adapted from IBM's ILE RPG Reference Manual:
D p7 s 7p 3 inz (1234.567)
D s9 s 9s 5 inz (73.73442)
D f8 s 8f inz (123.789)
D c15a s 15a inz (' 12345.6789 -')
D c15b s 15a inz (' + 9 8 7 . 6 5 4 ')
D result1 s 15p 5
D result2 s 15p 5
D result3 s 15p 5
* using numeric parameters
C EVAL result1 = %INT(p7) + 0.011
* "result1" is now 1234.01100.
C EVAL result2 = %INT(s9)
* "result2" is now 73.00000
C EVAL result3 = %INTH(f8)
* "result3" is now 124.00000.
* using character parameters
C EVAL result1 = %INT(c15a)
* "result1" is now -12345.00000
C EVAL result2 = %INTH(c15b)
* "result2" is now 988.00000
The second and third EVAL operations show the difference between %INT and %INTH: if the example used %INT instead of %INTH in the third EVAL operation, the result3 variable would contain 123.0000 instead of 124.00000.
Whatever %FLOAT(s) Your Boat
Finally, a quick word about %FLOAT: it works just like %INT, and it converts the numeric or character expression to float. If the value to convert is a character expression, the following rules apply:
- The sign is optional. It can be a plus sign (+) or a minus sign (-), but it must precede the numeric data.
- The decimal point is optional, and you can use either a period or a comma.
- If invalid numeric data is found, an exception occurs with status code 105.
- The exponent is optional. It can be either E or e. The sign for the exponent is optional, and it must precede the numeric part of the exponent.
- Blanks are allowed anywhere in the data. For example, + 3 , 5 E 9 is a valid parameter.
The first three rules are also applicable to %INT and %INTH. Just to consolidate all this information, here's an example adapted from IBM's ILE RPG Reference Manual:
D p1 s 15p 0 inz (1)
D p2 s 25p13 inz (3)
D c15a s 15a inz('-5.2e-1')
D c15b s 15a inz(' + 5 . 2 ')
D result1 s 15p 5
D result2 s 15p 5
D result3 s 15p 5
D result4 s 8f
* using numeric parameters
C EVAL result1 = p1 / p2
* "result1" is now 0.33000.
C EVAL result2 = %float (p1) / p2
* "result2" is now 0.33333.
C EVAL result3 = %float (p1 / p2)
* "result3" is now 0.33333.
C EVAL result4 = %float (12345)
* "result4" is now 1.2345E4
* using character parameters
C EVAL result1 = %float (c15a)
* "result1" is now -0.52000.
C EVAL result2 = %float (c15b)
* "result2" is now 5.20000.
C EVAL result4 = %float (c15b)
* "result4" is now 5.2E0
A Word About Fixed-Format Code
All the examples of this and the next TechTips were "downgraded" from free-format to fixed-format to keep the readers unfamiliar with "modern" RPG in the loop. But don't get me wrong: I don't advise writing new code in fixed-format! However, migrating to free-format can be a somewhat complicated process (especially inside our heads), and I'll get to that after preparing the ground with a few more tips that (I hope) will help you make a smoother transition from "old" to "modern" RPG.
The next TechTip will continue on this path, covering a few string-related BIFs as well as the conversion from numeric to character data types, which is another big use of MOVE and MOVEL. I want to hear from you: reader feedback is very important for writers! Comment, argue, agree, or disagree—just speak your mind in the Comments section below!
LATEST COMMENTS
MC Press Online