CategoryCOBOL

COBOL Code Optimization

To assist in the optimization of the code, you should use the OPTIMIZE compiler option. With the OPTIMIZE(STD) or OPTIMIZE(FULL) options in effect, you may receive optimizations that include:

  • eliminating unnecessary branches
  • simplifying inefficient branches
  • simplifying the code for the out-of-line PERFORM statement, moving the performed paragraphs in-line,where possible
  • simplifying the code for a CALL to a contained (nested) program, moving the called statements in-line,where possible
  • eliminating duplicate computations
  • eliminating constant computations
  • aggregating moves of contiguous, equal-sized items into a single move
  • deleting unreachable code

Additionally, with the OPTIMIZE(FULL) option in effect, you may also receive these optimizations:

  • deleting unreferenced data items and the associated code to initialize their VALUE clauses

Many of these optimizations are not available with OS/VS COBOL, but are available with IBM Enterprise COBOL. NOOPTIMIZE is generally used while a program is being developed when frequent compiles are necessary.

NOOPTIMIZE can make it easier to debug a program since code is not moved. However, IBM Enterprise COBOL now supports debugging programs compiled with the OPTIMIZE compiler option.

OPTIMIZE requires more CPU time for compiles than NOOPTIMIZE, but generally produces more
efficient run-time code. For production runs, OPTIMIZE is recommended.

WARNING: If your program relies upon unreferenced level 01 or level 77 data items, you should not use OPTIMIZE(FULL), since OPTIMIZE(FULL) will delete all unreferenced data items. One way to prevent the data item from being deleted by the OPTIMIZE(FULL) option is to refer to the data item in the
PROCEDURE DIVISION (for example, initialize the data item with a PROCEDURE DIVISION statement instead of with VALUE clauses).

Performance considerations using OPTIMIZE:

  • On the average, OPTIMIZE(STD) was 1% faster than NOOPTIMIZE, with a range of 7% faster to equivalent.
  • On the average, OPTIMIZE(FULL) was equivalent to OPTIMIZE(STD).

ARITH Compiler Option

ARITH affects the maximum number of digits that you can code for integers, and the number of digits used in fixed-point intermediate results. By specifying ARITH complier option we can control the maximum number of digits allowed for decimal numbers (packed decimal, zoned decimal and numeric-edited data items and numeric literals).

ARITH(EXTEND)  – Max. Number of digits 31.

ARITH(COMPAT) – Max. Number of digits 18.

Default is:

ARITH(COMPAT)

Abbreviations are: AR(C|E)

Arith-extend is performance hampering because of larger intermediate results.

When you specify

ARITH(EXTEND):

  • The maximum number of digit positions that you can specify in the
    PICTURE clause for packed-decimal, external-decimal, and numeric-edited data items is raised from 18 to 31.
  • The maximum number of digits that you can specify in a fixed-point numeric literal is raised from 18 to 31. You can use numeric literals with large precision anywhere that numeric literals are currently allowed, including:
    • Operands of PROCEDURE DIVISION statements
    • VALUE clauses (for numeric data items with large precision PICTURE)
    • Condition-name values (on numeric data items with large-precision PICTURE)
  • The maximum number of digits that you can specify in the arguments to NUMVAL and NUMVAL-C is raised from 18 to 31.
  • The maximum value of the integer argument to the FACTORIAL function is 29.
  • Intermediate results in arithmetic statements use extended mode.

When you specify ARITH(COMPAT) :

  • The maximum number of digit positions in the PICTURE clause for packed-decimal, external-decimal, and numeric-edited data items is 18.
  • The maximum number of digits in a fixed-point numeric literal is 18.
  • The maximum number of digits in the arguments to NUMVAL and NUMVAL-C is 18.
  • The maximum value of the integer argument to the FACTORIAL function is 28.
  • Intermediate results in arithmetic statements use compatibility mode.

 

INSPECT in COBOL

The INSPECT verb has two options, TALLYING and REPLACING. You can do one or the other or both. If both are done, the TALLYING IS DONE BEFORE THE replacing. Some versions of the INSPECT require that all the literals be in quotes. This may call for a redefination if the field is numeric.
In using the TALLYING format of the INSPECT, you are tallying into a field that is a counter. This field must be initialized to 0 before the inspect is done. Unsually this is done by a MOVE 0 to whatever the counter is called.

The TALLYING option of the INSPECT has multiple options – in fact, some versions have options beyond those required by the COBOL specifications:

    • You can tally ALL of something
    • You can tally just the LEADING occurances of something
    • You can just tally CHARACTERS
    • You can tally BEFORE or AFTER an INITIAL specified character

Example #1: This statement counts the number of occurrences of the digit 5 until the first space is encountered. If FLA = 256545 67 then after the INSPECT, CTRA would equal 3.
MOVE 0 TO CTRA.
INSPECT FLDA TALLY CTRA
    FOR ALL “5” BEFORE INTIAL SPACE.

Example #2: This statement counts the number of spaces in the field FLDB.
If FLB = 4 5 6 1 2 then after the INSPECT, CTRB would equal 4 since there is a space between each number.
MOVE 0 TO CTRB.
INSPECT FLDB TALLYING CTRB
    FOR ALL SPACES.

Example #3: In this example, the count of all characters before the first space is tallied. If FLDC is equal to 16AB5 6 then CTRC will contain the number 5 since 1, 6, A, B, and 5 proceed the space before the 6.
MOVE 0 TO CTRC.
INSPECT FLDC TALLYING CTRC
    FOR CHARACTERS BEFORE INITIAL SPACE.

Example #4: This statement counts all of the leading zeros in a field. Embedded or trailing zeros are counted. IF FLDD is equal to 00090020, then CTRD is equal to 3.
MOVE 0 TO CTRD.
INSPECT FLDD TALLYING CTRD
    FOR LEADING ZEROS.

Example #5: This statement counts all zeros in the field. IF FLDE is equal to 00090020, then CTRE will be equal to 6.
MOVE 0 TO CTRE.
INSPECT FLDE TALLYING CTRE
    FOR ALL ZEROS.
Example #6: This statement tallies for all zeroes that proceed the initial 2 In this case, CTRF will be 5. FLDF is equal to 00090020.
INSPECT FLDF TALLYING CTRF
    FOR ALL ZEROS BEFORE INITIAL 2.

Example #7: This statement counts the spaces before the number 5. In this example CTRG will be 3. FLDG has three spaces and then the number 1257 ( 1257).
INSPECT FLDG TALLYING CTRG
    FOR LEADING SPACE BEFORE INITIAL 5.

Example #8: This statement will replace all B with G. FLDH will start as ABCBDFB and will become AGCGDFG.
INSPECT FLDH REPLACING ALL “B” BY “G”.

Example #9: This replace will change all A to X. This means that AAABBAAA will become XXXBBAAA.

INSPECT FLDI REPLACING CHARACTERS BY “X”
    BEFORE INITIAL “B”.

Example #10: This will replace the first X with a 5. There ACXDGXB will become AC5DGXB.
INSPECT FLDJ REPLACING FIRST “X” BY “5”.

COBOL Numeric Data Types – COMP

The following common COBOL data types are discussed below:

  • Binary
  • Computational (comp)
  • Comp-1
  • Comp-2
  • Comp-3
  • Packed Decimal

BINARY
Specified for binary data items. Such items have a decimal equivalent consisting of the decimal digits 0 through 9, plus a sign. Negative numbers are represented as the two’s complement of the positive number with the same absolute value.  The amount of storage occupied by a binary item depends on the number  of decimal digits defined in its PICTURE clause:

Digits in PICTURE Clause Storage Occupied
1 through 4 2 bytes (halfword)
5 through 9 4 bytes (fullword)
10 through 18 8 bytes (doubleword) │
The leftmost bit of the storage area is the operational sign.

PACKED-DECIMAL
Specified for internal decimal items. Such an item appears in storage  in packed decimal format. There are 2 digits for each character  position, except for the trailing character position, which is  occupied by the low-order digit and the sign. Such an item can  contain any of the digits 0 through 9, plus a sign, representing a  value not exceeding 18 decimal digits.

The sign representation uses the same bit configuration as the 4-bit  sign representation in zoned decimal fields.

COMPUTATIONAL or COMP
Representation of the COMPUTATIONAL phrase is system-dependent and is  normally assigned to representations that yield the greatest  efficiency when arithmetic operations are performed on that system.

COMPUTATIONAL-1 or COMP-1
Specified for internal floating-point items (single precision).  COMP-1 items are 4 bytes long. The sign is contained in the first bit  of the leftmost byte and the exponent is contained in the remaining 7  bits. The last 3 bytes contain the mantissa.

COMPUTATIONAL-2 or COMP-2
Specified for internal floating-point items (double precision). COMP-2 items are 8 bytes long. The sign is contained in the first bit  of the leftmost byte and the remaining 7 bits contain the exponent.  The remaining 7 bytes contain the mantissa.

COMPUTATIONAL-3 or COMP-3 (internal decimal)
For VS COBOL II, this is the equivalent of PACKED-DECIMAL.

COMPUTATIONAL-4 or COMP-4 (binary)
For VS COBOL II this is the equivalent of BINARY.

COBOL Calendar & Date Functions

You need to know what date is 150 days from today (and this kind of stuff happens more often than you’d think)? Convert today to an integer date, add 150 to it and convert it back. No more checking which months you’re going through to see if it’s a 30 day or 31 day month. No more leap year calculations.

Some sample COBOL Date Example:

01  WS-TODAY         PIC 9(8).
01 WS-FUTURE-DATE PIC 9(8).
....
MOVE FUNCTION CURRENT-DATE (1:8) TO WS-TODAY.
COMPUTE WS-FUTURE-DATE = FUNCTION DATE-OF-INTEGER 
(FUNCTION INTEGER-OF-DATE (WS-TODAY) + 150)

Probably the most useful intrinsic function is CURRENT-DATE which is a replacement for ACCEPT DATE and ACCEPT TIME. CURRENT-DATE is Y2K-compliant, having a 4-digit year. This function returns a 20-character alphanumeric field which is laid out as follows:
01  WS-CURRENT-DATE-FIELDS.
05 WS-CURRENT-DATE.
10 WS-CURRENT-YEAR PIC 9(4).
10 WS-CURRENT-MONTH PIC 9(2).
10 WS-CURRENT-DAY PIC 9(2).
05 WS-CURRENT-TIME.
10 WS-CURRENT-HOUR PIC 9(2).
10 WS-CURRENT-MINUTE PIC 9(2).
10 WS-CURRENT-SECOND PIC 9(2).
10 WS-CURRENT-MS PIC 9(2).
05 WS-DIFF-FROM-GMT PIC S9(4).

So not only can you get the time down to the millisecond, but you can get the difference between your time and Greenwich Mean Time.

The function is used in a MOVE:
MOVE FUNCTION CURRENT-DATE TO WS-CURRENT-DATE-FIELDS

The other intrinsic date functions deal with converting between either Gregorian dates or Julian dates and an internal Integer format. This Integer format is simply the number of days since some predetermined, fixed date like 1/1/0001. These four conversion functions are:
* Convert from Gregorian to Integer formats
COMPUTE WS-INTEGER-DATE = FUNCTION INTEGER-OF-DATE (WS-DATE)

* Convert from Integer to Gregorian formats
COMPUTE WS-DATE = FUNCTION DATE-OF-INTEGER (WS-INT-DATE)

* Convert from Julian to Integer formats
COMPUTE WS-INTEGER-DATE = FUNCTION INTEGER-OF-DAY (WS-JUL-DATE)

* Convert from Integer to Julian formats
COMPUTE WS-JULIAN-DATE = FUNCTION DAY-OF-INTEGER (WS-INT-DATE)

All Gregorian and Julian dates are expected to have 4-digit years.

COMPUTE is OK because we’re only using integers here.

How many days between two dates?
COMPUTE WS-DAYS = FUNCTION INTEGER-OF-DATE (WS-DATE-1) -
FUNCTION INTEGER-OF-DATE (WS-DATE-2)

Converting between Gregorian and Julian formats used to be a pain also. Now:
COMPUTE WS-DATE = FUNCTION DATE-OF-INTEGER (FUNCTION
INTEGER-OF-DAY (WS-JULIAN))