How to move COMP-5 values to a Numeric field? - cobol

I am trying to move a COMP-5 variable(which I am receiving from some other system) to a numeric field. I have noticed when I display the COMP-5 variable I can see the value but when I try to move it the value in COMP-5 variable becomes zeros.I don't have any experience working with COMP-5. Can someone help me with this?
Code:
09 O-Xid.
12 O-Xid2-length PIC S9999 COMP-5 SYNC.
12 O-Xid2 PIC X(255).
09 WS-O-Xid.
12 WS-O-Xid2-length PIC 9999.
12 WS-O-Xid2 PIC X(255).
MOVE O-Xid2-length TO WS-O-Xid2-length
MOVE O-Xid2 TO WS-O-Xid2

MOVE as you've used does any necessary conversions between any numeric USAGE, as long as the data is valid.
The code misses the actual DISPLAY statement, I assume you've tested for valid data with DISPLAY O-Xid2-length (please specify the output).
The most likely reason that the target does not contain the source value would be:
the COBOL environment you use (you've neither specified the compiler not the options you used) doesn't truncate COMP-5 values according to ANSI/ISO - so it may contain "10000" and is then truncated on the MOVE because the target can't hold that value (standard truncation happening here keeps only the last 4 digits).
All other cases get to "there is not the data in the field that you think" - again: please specify both the ´DISPLAY` statement and the result.
Additional info to TRUNC(BIN): according to the docs:
BINARY sending fields are handled as halfwords, fullwords, or doublewords when the receiver is numeric
DISPLAY will convert the entire content of binary fields with no truncation.
DISPLAY would also show a value like 30000, I think the MOVE would in this case result to a zero value.
For other usages, it would be possible that the value stored in the variable is actually not valid data, but this does not apply to BINARY (or COMP-5 items). In this case the COBOL environment used could do some auto-correction on DISPLAY, but on MOVE just change the invalid value to ZERO; to check that you'd need to use either a debugger or otherwise hex-dump the value received.

Related

How to write an output which is longer than the maximum LRECL in COBOL?

Have you ever worked on VBS or FBS files with more than the maximum LRECL in COBOL?
I want to edit LOB (Large Object) records which are much longer than 32760, write them into files, and transfer them to an Unix server.
If you already have experience, it would be nice if you could give me some tips for processing.
Here is material on the considerations of Spanned records in COBOL
You can code RECORDING MODE S for spanned records in QSAM files that
are assigned to magnetic tape or to direct access devices. Do not
request spanned records for files in the HFS. You can omit the
RECORDING MODE clause. The compiler determines the recording mode to
be S if the maximum record length (in bytes) plus 4 is greater than
the block size set in the BLOCK CONTAINS clause.
For files with format S in your program, the compiler determines the
maximum record length with the same rules as are used for format V.
The length is based on your usage of the RECORD clause.
When creating files that contain format-S records and a record is
larger than the remaining space in a block, COBOL writes a segment of
the record to fill the block. The rest of the record is stored in the
next block or blocks depending on its length. COBOL supports QSAM
spanned records up to 32,760 bytes in length.
When retrieving files that have format-S records, a program can
retrieve only complete records.
Here is an explanation of storing records that are longer than 32,760 bytes. Segmented records are not supported via ISPF Edit. They are kind of an odd beast.
You can call C runtime routines from COBOL (or other LE-conforming languages).
[...]
Working-Storage Section.
01 CONSTANTS.
05 WS-FILE-OPTN PIC X(003) VALUE Z'rb'.
01 WORK-AREAS.
05 WS-FILE POINTER VALUE NULL.
05 WS-FILE-NM PIC X(255).
[...]
Procedure Division.
[...]
CALL 'FOPEN' USING
BY REFERENCE WS-FILE-NM
BY REFERENCE WS-FILE-OPTN
RETURNING WS-FILE
END-CALL
IF WS-FILE = NULL
[error handling, maybe call perror()]
END-IF
This way you can delegate the I/O to the C runtime and do the rest of your logic in COBOL.
Consult the C runtime library reference for documentation on required parameters to your chosen I/O functions.

Using an index from another table

If a table element (table without an index) is accessed using an index of another table it can give a Table overflow error on IBM Host. But the same program does not result in a crash or a message (even with debug options) when using GnuCOBOL (formerly OpenCOBOL).
e.g.
IDENTIFICATION DIVISION.
PROGRAM-ID. TSTPROGX.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 IX PIC 9(04) COMP VALUE ZERO.
01 VARS.
05 S-PART-C.
10 S-DETAIL OCCURS 100 TIMES
INDEXED BY S-SUB.
15 S-ACTUAL PIC 9(06) VALUE ZERO.
15 S-ACTUAL-A
REDEFINES S-ACTUAL
PIC X(06).
15 S-GRADE PIC X(02) VALUE LOW-VALUE.
05 POS-USED-ARRAY PIC X(999)
VALUE SPACE.
05 FILLER REDEFINES POS-USED-ARRAY
OCCURS 999.
10 FILLER-X PIC X .
88 POSITIONS-USED-X VALUE 'T'.
PROCEDURE DIVISION.
SET S-SUB TO 1
PERFORM VARYING IX FROM 1 BY 1 UNTIL IX > 999
SET S-SUB TO IX
SET POSITIONS-USED-X(S-SUB) TO TRUE
DISPLAY IX ":" FILLER-X(S-SUB)
END-PERFORM
GOBACK.
Is there a compiler option to issue warnings to avoid this kind of usage?
This error can be avoided by using the right usage.i.e, using the variable 'I-X', instead of using the index(S-SUB) of a different table.
SET POSITIONS-USED-X(I-X) TO TRUE
In general, exchanging index of independent tables(of different size) seems to be erroneous.
Presuming that by Host you mean Mainframe, using Enterprise COBOL, the link I originally included has the answer for you.
In Enterprise COBOL, you can use an index from one table to reference data on another table, even one which does not have an index (like your example), but unless the lengths of the data subordinate to the OCCURS is the same you will not get the results you expect.
With Enterprise COBOL and compiler option SSRANGE the code in your question will fail (as you are aware). Where will it fail? The length of the OCCURS associated with the index S-SUB is eight bytes. That length is effectively "inbuilt" into the index S-SUB. Dividing 999 (length of second table) by eight yields 124 (ignore the remainder), so an S-SUB being SET to 124 will be OK, and SET to 125 will not, because 125 will start at by 1,000, and you only have 999 bytes.
In GnuCOBOL the index does not have the length inbuilt, it is a simple integer relating directly to the occurence in the table. However, having got up to 100, you start overflowing the first table (where there is no compiler/run-time check) and 125 references later you go beyond the end of the second table, and with -g in your compile options will get a crash depending on how (and how much) the storage is allocated in the C program generated by the GnuCOBOL compiler. 225 would be the first point at which a crash could occur, but it may not do so at that point, and it may, or may not, later.
Basically, there's no way you can really expect the code to work, which you know, you just want to know how to set the compiler to check for it with GnuCOBOL. Currently, you can't.
Usually there is a field defined to hold the maximum entries in a table, and another defined to say how many are being used. When using entries, you first check to see the table is not full.
You could use LENGTH OF/FUNCTION LENGTH to protect against going over the end of a table as well.
You could combine the two approaches.
You just don't have a switch for GnuCOBOL that helps you here. The -g goes down to the C compiler. It gives you something, but not everything, and just depends.
Also, it is not, to my mind, a good idea to have a data-name which you use for subscripting named IX and an index named S-SUB. That will confuse a human reader of a program.
See this answer: https://stackoverflow.com/a/36254166/1927206 for some detail about using indexes from different tables.
IBM Enterprise COBOL can check that storage referenced using an index is within the table that the referenced-element is subordinate to. This is done with compiler option SSRANGE. If data outside the table is referenced (by any manner of subscripting, or by reference-modification) a run-time diagnostic message is produced. In all but the latest Enterprise COBOL compilers, that problem will cause an "abend" (an "abnormal end"). With the latest compilers, there are some sub-options to give more control.
This is not strictly checking the "bounds" of a table. For a one-dimensional table, the table-reference checking coincides with bounds-checking. For a multi-dimensional table it does not. The second and subsequent levels of subscript can be "wrong", but unless they cause a reference outside the table, this is unproblematic.
GnuCOBOL/OpenCOBOL does not have any checking for the use of subscripts or the reference of a table by subscripting/reference-modification. If you wanted to consider adding this yourself, you would be more than welcome. Or you could post it as a feature request. Visit https://sourceforge.net/p/open-cobol/discussion/?source=navbaring, but not everything.
See this answer: https://stackoverflow.com/a/36254166/1927206 for some detail about using indexes from different tables.
IBM Enterprise COBOL can check that storage referenced using an index is within the table that the referenced-element is subordinate to. This is done with compiler option SSRANGE. If data outside the table is referenced (by any manner of subscripting, or by reference-modification) a run-time diagnostic message is produced. In all but the latest Enterprise COBOL compilers, that problem will cause an "abend" (an "abnormal end"). With the latest compilers, there are some sub-options to give more control.
This is not strictly checking the "bounds" of a table. For a one-dimensional table, the table-reference checking coincides with bounds-checking. For a multi-dimensional table it does not. The second and subsequent levels of subscript can be "wrong", but unless they cause a reference outside the table, this is unproblematic.
GnuCOBOL/OpenCOBOL does not have any checking for the use of subscripts or the reference of a table by subscripting/reference-modification. If you wanted to consider adding this yourself, you would be more than welcome. Or you could post it as a feature request. Visit https://sourceforge.net/p/open-cobol/discussion/?source=navbar

Mainframe COBOL COMPUTE TRUNC Query

I wonder why there is different in the result for those two cases.
Working Storage:
WS-SUM-LEN PIC S9(4) COMP.
WS-LEN-9000 PIC 9(5) VALUE 9000.
WS-TMP-LEN PIC 9(5).
WS-FIELD-A PIC X(2000).
Case 1) COMPUTE WS-SUM-LEN = WS-LEN-9000 + LENGTH OF WS-FIELD-A
Result: WS-SUM-LEN = 1000
Case 2)
MOVE LENGTH OF WS-FIELD-A TO WS-TMP-LEN
COMPUTE WS-SUM-LEN = WS-LEN-9000 + WS-TMP-LEN
Result: WS-SUM-LEN = 11000
The compiler option is TRUNC(OPT). Why there is no trunc occur for case 2?
Binary fields in IBM's Enterprise COBOL
Warnings
Compiler option TRUNC determines how code for binary fields is generated.
Do not just up and change from your site's default setting of option TRUNC. The different settings for TRUNC can give different results.
Changing from TRUNC(BIN) to TRUNC(STD) will give different results for any values beyond the decimal-values represented by the PICture defining the field. For a signed field, the same applies for the negative value.
01 a-good-name BINARY PIC 99.
ADD 1 TO a-good-name
With TRUNC(STD) the result will be truncated once 99 is reached. With TRUNC(BIN) the result will be truncated once 65535 is reached (if the field were signed, the truncation would be at 99 as before for TRUNC(STD) and 32767 for TRUNC(BIN)).
Changing from TRUNC(BIN) to TRUNC(OPT), without program changes, is only possible if all, entirely all, usage of binary fields is limited to decimal-values represented by the PICture. Particular pieces of code may appear to "work", but it would be a massive coincidence if all use of binary fields gave the same result between the two compiler options, on your system.
It is similar for changing from TRUNC(STD) to TRUNC(OPT). Although the amount of coincidence for working would be smaller, this would increase a false sense of security leaving the potential for subtle differences to be missed for some time.
Changing from genuine use of TRUNC(OPT) to either TRUNC(STD) or TRUNC(BIN) is possible without effort. However, why would you want to?
However, if your use is not genuine (using TRUNC(OPT) with data that does not conform to PICture), then your original results are unreliable, and you will get differences if changing to TRUNC(STD) and likely get difference changing to TRUNC(BIN).
In short, changing the site-default for compiler option TRUNC is something to be considered very carefully, and must include provision for verification of results.
Sites do at times make such a change, the only ones I know of are TRUNC(BIN) (mostly) and TRUNC(STD) to TRUNC(OPT), for performance reasons. These have been done as projects, not just by changing the option and blundering on from there.
Do not override the site-default for TRUNC within systems. If you have programs which are using the same binary data (from files, databases, inter-program communication, messages, or any other way) and they don't all treat the data in the same way, it is asking for trouble.
Some myths
Further explanation will be given later in the text.
There is a difference between TRUNC(BIN) and making all your binary
fields COMP-5 (or COMPUTATIONAL-5).
There is no difference whatsoever. When TRUNC(BIN) is specified, the compiler simply treats all binary fields as COMP-5.
Native-binary is faster than COBOL binary (a binary field with decimal limits defined by the PICture clause).
Although the term itself makes many experienced people think it will be faster ("it'll be like when I code it myself in Assembler") it is in fact slower, on the whole. The slowing-down increases as the field-size increases.
Native-binary (COMP-5/COMPUTATIONAL-5) does not truncate.
It does. It truncates to field-size. Because it truncates to field-size, the intermediate fields must always be larger than the source fields, which means more instructions must be used, and different instructions.
Also, and important to know, the ON SIZE ERROR clause (which can be used with all arithmetic verbs) always only uses the PICture clause to determine that a size-error has occurred. That is, if you have a COMP-5 PIC S9(4), which can contain a maximum positive value of 32,767 and do this:
MULTIPLY that-field BY 10 GIVING that-field
ON SIZE ERROR
DISPLAY "Busted"
END-MULTIPLY
Any value above 9999 will cause the DISPLAY to be processed.
Which really means "don't use ON SIZE ERROR with COMP-5 or TRUNC(BIN)".
TRUNC(OPT) generates optimal code.
In isolation, it does. However this does not preclude further optimisations from compiler option OPTIMIZE/OPT across a wider context.
When using binary fields, always use the maximum PICture for the size of the field
A binary field with 1-4 digits will occupy a half-word, two bytes of storage. With 5-9 digits, a word, or a fullword, of four bytes. With 10-18 digits, a double-word of eight bytes.
The aged recommendation is to always specify four digits, nine digits and 18 digits (well, no-one really goes above nine, do they...?).
This is advice I've received in the past, and given out myself. However, in Enterprise COBOL it is not good advice.
The best advice here is to define the number of digits needed. This will at times improve performance, will never degrade performance, and will make the program easier to understand by best describing the data.
When using binary fields, always make them signed.
More advice I've received and given in the past. Untrue with Enterprise COBOL. If a field can contain a negative value, make it signed. Otherwise make it unsigned.
At times, with interfaces, it is not explicit whether a field should be signed. However, it will be explicit from the maximum value expected. As will the field definition (the USAGE).
For instance, an SQL VARCHAR as a host-variable can have a maximum size of 32767 bytes. Since the actual length is held in a two-byte binary field, the field should be signed. Any value "above" 32767 will be misinterpreted by DB2/SQL.
Since nine decimal digits can fully fit within a word/fullword, there is no problem using nine decimal digits for a COMP/COMP-4/BINARY definition (without TRUNC(BIN)).
Since the compiler has to take care of decimal truncation, and since anything which could lead to truncation would require the "next size up", a binary field of nine digits can require a double-word intermediate field. So requires code to convert to a double-word, and convert the result back from a double-word to a word. If nine digits are required, it will generally be better to define 10 digits and save on the conversions.
Note
The above is all known to hold true for Enterprise COBOL up to V4.2.
IBM has entirely rewritten the code-generation and optimisation (now at two possible levels of optimisation) For Enterprise COBOL V5. There is considerable improvement in the treatment of binary fields, including, for instance, only doing the truncation of values once it is known that truncation is necessary. I am not aware that the use of V5 changes anything here other than the scale of performance differences. All general usage of binary fields should be faster with V5 than with earlier versions of Enterprise COBOL.
Binary fields
COBOL, for binary fields, uses decimal maxima determined by the PICture size.
Such a field with PIC 9 can contain a maximum value of 9 before truncation. If signed, the range of values is -9 to +9. Values outside that range will be truncated.
For PIC 99, 99, and if signed -99 to 99.
For PIC 999, 999,and if signed -999 to 999.
You get the pictu... idea.
It is down to the compiler-implementation as to how those values are stored.
Indeed, according to the Standard, COBOL only recently (1985) had support for binary fields (USAGE BINARY). Which and how actual "non-display" fields were supported was down to USAGE COMPUTATIONAL, whose specifics were compiler-dependent.
Generally across compilers COMP, COMP-1 and COMP-2 (binary, with decimal maxima, short floating-point and long floating-point) are standard, though not part of the Standard. Beyond COMP-2, what the field definitions mean can vary amongst compilers.
So, first recommendation, suggest that your local site standards use BINARY instead of COMP for new code (and PACKED-DECIMAL instead of COMP-3, for packed-decimal fields). BINARY (and COMP-4) within Enterprise COBOL is simply an alias of COMP, so there is absolutely no problem in doing this.
There is another type of binary field, which is the native-binary field. In Enterprise COBOL this is USAGE COMP-5.
COMP-5 has its field-size determined by the PICture definition, but its maxima are that of the full bit-pattern possible for the field size. A PIC S9(4) COMP-5 can contain -32768 to 32767.
Note at this point that a native-binary field, and this may seem counter-intuitive, generally needs more generated machine-code to support its use. This is because it truncates to field-size, rather than PICture.
Note also that there is one place where this does not happen, which is ON SIZE ERROR, which will be true if the value exceeds the PICture size. Which means, to my mind, don't use ON SIZE ERROR with COMP-5 (or TRUNC(BIN), see soon) fields.
Compiler option TRUNC
The compiler option TRUNC defines how machine-code is generated for binary fields. There are three options:
TRUNC(BIN)
Truncation to field-size.
This treats all the non-native-binary fields in the program (COMP/COMP-4/BINARY) as native-binary (as though they had been defined as COMP-5).
This allows the full range of bit patterns to be used, but has impacts on performance.
TRUNC(STD)
Truncation to PICture size.
Generates machine-code for the COBOL Standard truncation to PICture size. PIC 9(n) can contain no more than n significant digits, they will be truncated when the field is a "target" (field value changes).
TRUNC(OPT)
Truncation of any type only used if it happens to be convenient.
I describe this as being a contract between the coder and the compiler. The coder contracts to never (as in never) allow a value to exceed the PICture size. The compiler contracts to always get it right in such a case.
If the coder breaks the contract the coder is entirely to blame for the ensuing rubbish.
When to use each setting of TRUNC (further recommendation)
BIN Never. Use COMP-5 for individual fields where they require access to all bits (pay attention to SQL and CICS "system" fields, and external data from non-Mainframe sources, and inter-language communication between COBOL and JAVA/C/C++ and anywhere else where the data-maxima for a field are beyond the PICture and it is not possible to make the field bigger (as the actual logical definition of the field size is outside your program).
STD use this unless all, as in all, your data always, as in always, conforms to PICture.
OPT use this only, as in only, if all, as in all, your data always, as in always, conforms to PICture.
If you have COMP PIC 99, for instance, you must not, when using OPT, allow that to have a value of 99, and then add one to it. Or anything similar
The Answer
You used TRUNC(OPT), entering into the contract. You immediately broke the contract. It is your fault.
Warning
If your site is using TRUNC(OPT) and not everyone is fully aware of the implications, you will, as in will, have problems.
Substantiation of the Myths from above
There is a difference between TRUNC(BIN) and making all your binary
fields COMP-5 (or COMPUTATIONAL-5).
Define two fields in small program. They should be defined as COMP/COMP-4/BINARY (or COMPUTATIONAL/COMPUTATIONAL-4 if that is your bent).
In the program, add a literal to each of the fields (do this with two separate statements, to make it easier to follow, unless you are experience with the generated code in a listing).
Compile the program with compiler options LIST,NOOFFSET (this will produce, in the compiler listing, output showing the generated machine-code in a so-called "pseudo-assembler" format) and TRUNC(BIN).
Copy the program. In the copy, change the USAGE of the two fields to COMP-5 (or COMPUTATIONAL-5).
Compile this program, again with LIST,NOOFFSET but this time the value for TRUNC is irrelevant as it does not affect COMP-5 fields.
Compare the output listings. If there is one byte difference, eat someone's hat.
Native-binary is faster than COBOL binary (a binary field with decimal limits defined by the PICture clause).
From this discussion at IBM's COBOL Cafe: https://www.ibm.com/developerworks/community/forums/html/topic?id=ae9ef6bc-6e4e-43f8-a814-e66bea25fb8c&ps=25
Here's a multiply of a PIC 9(3) by a PIC 9(5).
With TRUNC(STD)
000023 MULTIPLY
000258 5820 8008 L 2,8(0,8) PIC9-5
00025C 4C20 8000 MH 2,0(0,8) PIC9-3
000260 5020 8010 ST 2,16(0,8)
With TRUNC(BIN)
000019 MULTIPLY
00023C 4820 8030 LH 2,48(0,8) PICS9-4
000240 5840 8038 L 4,56(0,8) PICS9-8
000244 8E40 0020 SRDA 4,32(0)
000248 5D40 C000 D 4,0(0,12) SYSLIT AT +0
00024C 4E50 D120 CVD 5,288(0,13) TS2=16
000250 F154 D110 D123 MVO 272(6,13),291(5,13) TS2=0
000256 4E40 D120 CVD 4,288(0,13) TS2=16
00025A 9110 D115 TM 277(13),X'10' TS2=5
00025E D204 D115 D123 MVC 277(5,13),291(13) TS2=5
000264 4780 B05C BC 8,92(0,11) GN=10(00026C)
000268 9601 D119 OI 281(13),X'01' TS2=9
00026C GN=10 EQU *
00026C 4E20 D120 CVD 2,288(0,13) TS2=16
000270 FC82 D111 D125 MP 273(9,13),293(3,13) TS2=1
000276 D202 D128 C008 MVC 296(3,13),8(12) TS2=24
00027C D204 D12B D115 MVC 299(5,13),277(13) TS2=27
000282 4F20 D128 CVB 2,296(0,13) TS2=24
000286 F144 D12B D110 MVO 299(5,13),272(5,13) TS2=27
00028C 4F50 D128 CVB 5,296(0,13) TS2=24
000290 5C40 C000 M 4,0(0,12) SYSLIT AT +0
000294 1E52 ALR 5,2
000296 47C0 B08E BC 12,142(0,11) GN=11(00029E)
00029A 5A40 C004 A 4,4(0,12) SYSLIT AT +4
00029E GN=11 EQU *
00029E 1222 LTR 2,2
0002A0 47B0 B098 BC 11,152(0,11) GN=12(0002A8)
0002A4 5B40 C004 S 4,4(0,12) SYSLIT AT +4
0002A8 GN=12 EQU *
0002A8 5050 8040 ST 5,64(0,8)
It doesn't take any knowledge of IBM Assembler to work out which of those two pieces of code is going to run more quickly.
The difference in the line-numbers (19 Vs 23) is just down to the fact that TRUNC(BIN) makes the PICture size irrelevant, so where I had three calculations doing the same thing with different size fields, for TRUNC(BIN) the code for each was the same, because the size of each field is the same, a word/fullword of four bytes.
Native-binary (COMP-5/COMPUTATIONAL-5) does not truncate.
See the code immediately above. It is so massive due to the need to provide truncation. The need to provide decimal truncation is down to the COBOL Standard, it's what must happen in the language.
TRUNC(OPT) generates optimal code.
The code generated will always be the most efficient for that code-sequence. The same code-sequence will always generate the same code, before optimisation.
However, the optimizer is capable of spotting that a particular undisturbed state is available for a source-field earlier in the program, and replace part or all of the TRUNC(OPT) code with code relying on the previously-available value.
When using binary fields, always use the maximum PICture for the size of the field
From the same IBM COBOL Cafe discussion referenced above, with these definitions:
01 PIC9-3 BINARY PIC 999.
01 PIC9-5 BINARY PIC 9(5).
01 THE-RESULT8 BINARY PIC 9(8).
01 PIC9-4 BINARY PIC 9(4).
01 PIC9-8 BINARY PIC 9(8).
01 THE-RESULT BINARY PIC 9(8).
And these calculations:
MULTIPLY PIC9-4 BY PIC9-8
GIVING THE-RESULT
MULTIPLY PIC9-3 BY PIC9-5
GIVING THE-RESULT8
Here's the generated code for TRUNC(STD):
000021 MULTIPLY
000248 4830 8018 LH 3,24(0,8) PIC9-4
00024C 5C20 8020 M 2,32(0,8) PIC9-8
000250 5D20 C000 D 2,0(0,12) SYSLIT AT +0
000254 5020 8028 ST 2,40(0,8) THE-RESULT
000023 MULTIPLY
000258 5820 8008 L 2,8(0,8) PIC9-5
00025C 4C20 8000 MH 2,0(0,8) PIC9-3
000260 5020 8010 ST 2,16(0,8)
The first block of pseudo-assembler is with the number of digits in the PICture being the maximum that give the same field-size. A BINARY PIC 9(3) occupies a half-word, and 9(4) is the largest that can appear in a half-word. A PIC 9(5) occupies a word/fullword, and, given Myth 7, eight digits is used for that (to be fair to this particular Myth).
The second block is with the number of digits which represent the data accurately, and which don't happen to require truncation when a multiplication is carried out.
Using the "full-size" PICtures guarantees that unnecessary truncation will always occur.
The difference in the number of instructions is small, and LH is faster than L, so plus to the full-size on that. But M is much slower than L, and MH is slower than L but faster than M. So plus to the optimal size on that. And the D (a divide, which is slow, slow) is not required at all in the second block (because no truncation is required). So bad-boy to the full-size fields on that.
The code for TRUNC(OPT) is also faster for the optimal-size fields, although the difference between the two is not as great (because TRUNC(OPT) in this code-sequence decides it does not need the truncation to base-10 and would not in a million years consider the truncation to field-size).
When using binary fields, always make them signed.
Again from the same IBM COBOL Cafe discussion, here's same-length signed fields Vs unsigned fields, TRUNC(STD):
000019 MULTIPLY
000238 4830 8030 LH 3,48(0,8) PICS9-4
00023C 5C20 8038 M 2,56(0,8) PICS9-8
000240 5D20 C000 D 2,0(0,12) SYSLIT AT +0
000244 5020 8040 ST 2,64(0,8) THE-RESULTS
000021 MULTIPLY
000248 4830 8018 LH 3,24(0,8) PIC9-4
00024C 5C20 8020 M 2,32(0,8) PIC9-8
000250 5D20 C000 D 2,0(0,12) SYSLIT AT +0
000254 5020 8028 ST 2,40(0,8)
The code is different from the above when compiled with both TRUNC(OPT) and TRUNC(BIN), but each of the code-sequences in both cases is identical in those options.
The presence or absence of a sign makes no difference to the code generated.
Except in one case. Where Myth 7 comes into play. With a nine-digit binary, using a signed vs unsigned field does generate less code, but that code generated is more code than if using eight digits.
Since nine decimal digits can fully fit within a word/fullword, there is no problem using nine decimal digits for a COMP/COMP-4/BINARY definition (without TRUNC(BIN)).
From the IBM Enterprise COBOL Version 4 Release 2 Performance Tuning paper, pp32-33:
The following shows the general performance considerations (from most
efficient to least efficient) for the number of digits of precision
for signed binary data items (using PICTURE S9(n) COMP) using
TRUNC(OPT):
n is from 1 to 8
for n from 1 to 4, arithmetic is done in halfword instructions where
possible for n from 5 to 8, arithmetic is done in fullword
instructions where possible
n is from 10 to 17 arithmetic is done in doubleword format
n is 9
fullword values are converted to doubleword format and then doubleword
arithmetic is used (this is SLOWER than any of the above)
n is 18 doubleword values are converted to a higher precision format
and then arithmetic is done using this higher precision (this is the
SLOWEST of all for binary data items)
There is a similar issue with TRUNC(STD). TRUNC(BIN) already has the built-in slowness for the number of digits 1-9, so is not further affected.
From the publicly available documentation :
TRUNC(OPT) is a performance option. When TRUNC(OPT) is in effect, the compiler assumes that data conforms to PICTURE specifications in USAGE BINARY receiving fields in MOVE statements and arithmetic expressions. The results are manipulated in the most optimal way, either truncating to the number of digits in the PICTURE clause, or to the size of the binary field in storage (halfword, fullword, or doubleword).
Tip: Use the TRUNC(OPT) option only if you are sure that the data being moved into the binary areas will not have a value with larger precision than that defined by the PICTURE clause for the binary item. Otherwise, unpredictable results could occur. This truncation is performed in the most efficient manner possible; therefore, the results are dependent on the particular code sequence generated. It is not possible to predict the truncation without seeing the code sequence generated for a particular statement.
Read the "Tip" very carefully and see what it means for your situation. (Hint : it means it does not make sense to ask the question you did because it literally says that "whatever happens, it was unpredictable" or iow "there is no explanation for what happens").
To make the compiler behaviour predictable, switch to either TRUNC(BIN) or TRUNC(STD). STD is good for standards compliance but bad for CPU usage, BIN is good for CPU usage but requires you to be a bit careful (because decimal truncation simply will not happen).

Allocation of Memory in Variable-Length Tables

Say I have the following variable-length table defined in WORKING-STORAGE...
01 SOAP-RECORD.
05 SOAP-INPUT PIC X(8) VALUE SPACES.
05 SOAP-STATUS PIC 9 VALUE ZERO.
05 SOAP-MESSAGE PIC X(50) VALUE SPACES.
05 SOAP-ITEMS OCCURS 0 TO 500 TIMES
DEPENDING ON ITEM-COUNT
INDEXED BY ITEM-X.
10 SI-SUB-ITEMS OCCURS 0 TO 100 TIMES
DEPENDING ON SUB-COUNT
INDEXED BY SUB-X.
15 SS-KEY PIC X(8) VALUE SPACES.
15 SS-AMOUNT PIC -9(7).99 VALUE ZEROS.
15 SS-DESCR PIC x(100) VALUE SPACES.
When this program runs, will it initially allocate as much space as this table could possibly need, or is it more dynamic about allocating memory? I would guess that the DEPENDING ON clause would make it more dynamic in the sense that it would allocate more memory as the ITEM-COUNT variable is incremented. A co-worker tells me otherwise, but he is not 100% sure. So I would really like to know how this works in order to structure my program as efficiently as possible.
PS: Yes, I am writing a new COBOL program! It's actually a CICS web service. I don't think this language will ever die :(
You don't mention which compiler you're using, but, at least up through the current, 2002, COBOL standard, the space allocated for an OCCURS...DEPENDING ON (ODO) data item is not required to be dynamic. (It's really only the number of occurrences, not the length, of the data item that varies.) Although your compiler vendor may've implemented an extension to the standard, I'm not aware of any vendor that has done so in this area.
The next, but not yet approved, revision of the standard includes support for dynamic-capacity tables with a new OCCURS DYNAMIC format.
In the CICS world, OCCURS DEPENDING ON (ODO) can be used to create a
table that is dynamically sized at run time. However, the way you are declaring
SOAP-RECORD will allocate enough memory to hold a record of maximum size.
Try the following:
First, move the SOAP-RECORD into LINKAGE SECTION. Items declared
in the linkage section do not have any memory allocated for them. At this
point you only have a record layout. Leave the declaration of
ITEM-COUNT and SUB-COUNT in WORKING-STORAGE.
Next, declare a pointer and a length in WORKING-STORAGE something like:
77 SOAP-PTR USAGE POINTER.
77 SOAP-LENGTH PIC S9(8) BINARY.
Finally in the PROCEDURE DIVISION: Set the size of the array
dimensions to some real values; allocate the
appropriate amount of memory and then connect the two. For example:
MOVE 200 TO ITEM-COUNT
MOVE 15 TO SUB-COUNT
MOVE LENGTH OF SOAP-RECORD TO SOAP-LENGTH
EXEC CICS GETMAIN
BELOW
USERDATAKEY
SET(SOAP-PTR)
FLENGTH(SOAP-LENGTH)
END-EXEC
SET ADDRESS OF SOAP-RECORD TO SOAP-PTR
This will allocate only enough memory to store a SOAP-RECORD with 200 SOAP-ITEMS
each of which contain 15 SI-SUB-ITEMS.
Note that the LENGTH OF register gives you the size of SOAP-RECORD
based on the ODO object values (ITEM-COUNT, SUB-COUNT) as opposed to
the maximum number of OCCURS.
Very important... Don't forget to deallocate the memory when your done!

COBOL Confusion

Hey, everyone. I'm having a bit of trouble in a coding project that I'm trying to tackle in the zOS environment using COBOL. I need to read a file in and put them into an indexed table (I know there will be less than 90 records).
The thing that is throwing me is that we are bound by the parameters of the project to use a variable called "Table-Size" (set to zero at declaration).
Given all that, I need to do something like "Occurs 1 to 90 times Depending on Table-Size", but I don't understand how that will work if table-size has to (as far as I can tell) because table-size is incremented along with each entry that is added to the table. Can anyone please clear this up for me?
Thanks!
It sounds like your primary concern is: how does the compiler know how much to allocate in the array if the size changes at run-time?
The answer is that it allocates the maximum amount of space (enough for 90 entries). Note that this is for space in working storage. When the record is written to a file, only the relevant portion is written.
An example:
01 TABLE-SIZE PIC 9
01 TABLE OCCURS 1 TO 9 TIMES DEPENDING ON TABLE-SIZE
03 FLD1 PIC X(4)
This will allocate 36 characters (9 multiplied by 4) for TABLE in working storage. If TABLE-SIZE is set to 2 when the record is written to a file, only 8 characters of TABLE will be written (over and above the characters written for TABLE-SIZE, of course).
So, for example, if the memory occupied by TABLE was AaaaBbbbCcccDdddEeeeFfffGgggHhhhIiii, the date written to the file may be the shortened (including size): 2AaaaBbbb.
Similarly, when the record is read back in, both TABLE-SIZE and the relevant bits of TABLE will be populated from the file (setting only the size and first two elements).
I don't believe that the unused TABLE entries are initialised to anything when that occurs. It's best to assume not anyway, and populate them explicitly if you need to add another item to the table.
For efficiency, you may want to consider setting the TABLE-SIZE to USAGE IS COMP.
We don't have quite enough information here, but the basic thing is that the variable named in the DEPENDING ON clause has to have a count of the variable number of groups. So you need something like
01 TABLE-SIZE PIC 99
01 TABLE OCCURS 1 TO 90 TIMES
DEPENDING ON TABLE-SIZE
03 FIELD-1
03 FIELD-2
and so on.
See this article or this article at Publib.

Resources