How to convert Decimal Values to Strings in COBOL - cobol

Given following code:
VAR X PIC S9(7)V9(2).
VAR Y PIC X(15)
Following code having compile error.
MOVE X TO Y. * compile error.
the error message is something like this "cannot move non-integer numbers to alphanumeric variable"
is there any way to fix this issue without making use of another variables (e.g. display vars) ?

The fix sometimes involves REDEFINES as in:
01.
05 Y PIC X(15).
05 X REDEFINES Y PIC S9(7)V9(2).
Notice that X occupies less storage than Y so X can REDEFINE Y but not the other way round. Since both X and Y now occupy the same physical storage, the MOVE can be dropped as the following program and output illustrate:
IDENTIFICATION DIVISION.
PROGRAM-ID. EXAMPLE.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 Y PIC X(15).
01 X REDEFINES Y PIC S9(7)V9(2).
PROCEDURE DIVISION.
MOVE -1234567.89 TO X
DISPLAY 'X: >' X '< Y: >' Y '<'
.
Output:
X: >12345678R< Y: >12345678R <
As you can quickly see, the result is probably not what you were hoping for since Y does not contain a human readable formatted number (i.e. one with a leading sign and a decimal point).
So my advice to you is don't try bend COBOL into something that it is not. Use the language as it was intended to be used. What you probably need to do is something along the lines of:
IDENTIFICATION DIVISION.
PROGRAM-ID. EXAMPLE.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 Y PIC X(15).
01 X PIC S9(7)V9(2).
01 T PIC -9(7).99.
PROCEDURE DIVISION.
MOVE -1234567.89 TO X
MOVE X TO T
MOVE T TO Y
DISPLAY 'X: >' X '< Y: >' Y '<'
GOBACK
.
Which outputs:
X: >12345678R< Y: >-1234567.89 <
Yes, the above program uses an additional variable in the middle to convert numeric format to display format, but that is exactly how the language was designed. Long winded but very straight forward. At the end of the exercise variable Y contains something that is readable and makes sense to the normal human eye.

Depending on what you want Y to contain, no.
01 VARS.
05 X PIC S9(7)V9(2).
05 Y REDEFINES X PIC X(9).
05 Z PIC -9(7).99.
05 Q PIC X(11).
MOVE X TO Z
MOVE Z TO Q
DISPLAY Y
DISPLAY Q
Try it and see what gives you the answer you want.
Caveat, this was just freehand, I haven't tried compiling it.

IDENTIFICATION DIVISION.
PROGRAM-ID. EXAMPLE.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 Y PIC X(15).
01 T REDEFINES Y PIC -(5)9(7).99.
01 U REDEFINES Y PIC -9(7).99B(4).
01 X PIC S9(7)V9(2).
PROCEDURE DIVISION.
MOVE -1234567.89 TO X
MOVE X TO T
DISPLAY 'X: >' X '< Y: >' Y '<'
MOVE X TO U
DISPLAY 'X: >' X '< Y: >' Y '<'
GOBACK
.
T gives right-alignment, U gives left-alignment. As both REDEFINES occupy the full 15 bytes, there is no need to take account of any value in Y prior to the MOVEs to T or U.
Output is:
X: >12345678R< Y: > -1234567.89<
X: >12345678R< Y: >-1234567.89 <

Related

COBOL supress last number while summing two decimal numbers

According to the COBOL code below when I try to sum WS-NUM1 with WS-NUM2, COBOL seems to supress the last number. For example: variable WS-NUM1 and WS-NUM2 are 10.15, I get 20.20 as result but expected 20.30. What's wrong?
WS-NUM1 PIC 9(2)V99.
WS-NUM2 PIC 9(2)V99.
WS-RESULTADO PIC 9(2)V99.
DISPLAY "Enter the first number:"
ACCEPT WS-NUM1.
DISPLAY "Enter the second number:"
ACCEPT WS-NUM2.
COMPUTE WS-RESULTADO = WS-NUM1 + WS-NUM2.
Thanks in advance.
PIC 9(2)v99 defines a variable with an implied decimal place not a real one. You're trying to enter data containing a decimal point and it's not working because you have to strip out the '.' to get the numeric part of your data to properly fit in the 4 bytes that your working storage area occupies.
PROGRAM-ID. ADD2.
data division.
working-storage section.
01 ws-num-input pic x(5).
01 WS-NUM1 PIC 9(2)V99 value 0.
01 redefines ws-num1.
05 ws-high-num pic 99.
05 ws-low-num pic 99.
01 WS-NUM2 PIC 9(2)V99 value 0.
01 redefines ws-num2.
05 ws-high-num2 pic 99.
05 ws-low-num2 pic 99.
01 WS-RESULTADO PIC 9(2)V99.
PROCEDURE DIVISION.
DISPLAY "Enter the first number:"
*
accept ws-num-input
unstring ws-num-input delimited by '.'
into ws-high-num, ws-low-num
DISPLAY "Enter the second number:"
accept ws-num-input
unstring ws-num-input delimited by '.'
into ws-high-num2, ws-low-num2
*
COMPUTE WS-RESULTADO = WS-NUM1 + WS-NUM2.
DISPLAY WS-RESULTADO
STOP RUN
.
This is just a simple demonstration. In a real world application you would have to insure much more robust edits to ensure that valid numeric data was entered.
If I declare it like this
01 WS-NUM1 PIC 9(2)V99.
01 WS-NUM2 PIC 9(2)V99.
01 WS-RESULTADO PIC 9(2)V99.
and define and sum them up like this
SET WS-NUM1 TO 10.15.
SET WS-NUM2 TO 10.15.
COMPUTE WS-RESULTADO = WS-NUM1 + WS-NUM2.
DISPLAY WS-RESULTADO.
I get the expected result of 20.30.
This looks like a job for a special type of PICture : Edited picture
Indeed you seem to know about the vanilla PICture clause (I'm writing PICture because as you may know it you can either write PIC or PICTURE).
A vanilla number PIC contains only 4 different symbols (and the parentheses and numbers in order to repeat some of the symbols)
9 : Represents a digit. You can repeat by using a number between parentheses like said before.
S : Means that the number is signed
V : Show the position of the implicit decimal point
P : I've been told that it exists but I honestly never found it in the codebase of my workplace. Its another kind of decimal point used for scaling factors but I don't know much about it.
But there are other symbols.
If you use theses other mysterious symbols the numeric PIC becomes an edited numeric PIC. As its name says, an edited PICture is made to be shown. It will allow you to format your numbers for better presentation or to receive number formatted for human reading.
Once edited, you cannot use it to make computations so you will have to transfer from edited to vanilla to perform computations on the latter. And you move from vanilla to edited in order to display your results.
So now I shall reveal some of these mysterious symbols :
B : Insert a blank at the place it is put
0 : Insert a zero at the place it is put
. : Insert the decimal point at the place it is put
: Insert a + if the number is positive and a - if the number is negative
Z : Acts like a 9 if the digits it represents has a value different than 0. Acts like a blank if the digits has the value of 0.
To my knowledge there are also : / , CR DB * $ -
You can look up for it on the internet. They really show the accountant essence of cobol.
For your problems we are really interested by the "." which will allow us to take into account the decimal point you have the write when you type down your input.
For a bonus I will also use Z which will make your result looks like 2.37 instead of 02.37 if the number is less than ten.
Note that you cannot use the repeating pattern with parenthesis ( 9(03) for instance) when describing an edited picture ! Each digits has to represented explicitly
IDENTIFICATION DIVISION.
PROGRAM-ID. EDITCOMP.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-NUM1-EDITED PIC 99.99.
01 WS-NUM2-EDITED PIC 99.99.
01 WS-NUM1-CALC PIC 9(2)V99.
01 WS-NUM2-CALC PIC 9(2)V99.
01 WS-RESULTADO-EDITED PIC Z9.99.
PROCEDURE DIVISION.
ACCEPT WS-NUM1-EDITED.
ACCEPT WS-NUM2-EDITED.
MOVE WS-NUM1-EDITED TO WS-NUM1-CALC.
MOVE WS-NUM2-EDITED TO WS-NUM2-CALC.
COMPUTE WS-RESULTADO-EDITED = WS-NUM1-CALC + WS-NUM2-CALC.
DISPLAY WS-RESULTADO-EDITED.
STOP RUN.
You should note that there also exist edited alphanumeric picture. You can insert Blank (B), zeroes (0) or / (/) in it.

How to move the last digit to the first position of a number in cobol

Say I have the number 123456, how can i move the 6 to the beginning so it becomes 612345?
needs to work if the number has fewer digits like 123 becoming 312.
many thanks in advance.
This is a general purpose method that will work with any integer from 2 to 32 digits. The number must be usage display.
working-storage section.
1 a-number pic 9(6) value 123456.
1 b-number pic 9(3) value 123.
1 work pic x(32).
1 len-of-number binary pic 9(4).
procedure division.
begin.
display a-number
move a-number (1:) to work
perform swap-digit
move work to a-number (1:)
display a-number
display space
display b-number
move b-number (1:) to work
perform swap-digit
move work to b-number (1:)
display b-number
stop run
.
swap-digit.
move 0 to len-of-number
inspect work tallying
len-of-number for characters before space
move function reverse (work (1:len-of-number))
to work
move function reverse (work (2:len-of-number - 1))
to work (2:len-of-number - 1)
.
Output:
123456
612345
123
312
This is the solution. Just MOVE your input to the VAR-INPUT. It is a alphanumeric picture clause, but it doesn't matter because you want a string as output.
Also I chose random picture clause lengths, you can choose whatever length you want.
WORKING-STORAGE SECTION.
01 VAR-INPUT PIC X(20).
01 VAR1 PIC X(10).
01 VAR2 PIC X(10).
01 RESULT PIC X(20).
01 L PIC 9(02).
01 OFFSET PIC 9(02).
PROCEDURE DIVISION.
COMPUTE L = LENGTH OF VAR-INPUT
COMPUTE OFFSET = L - 1
MOVE VAR-INPUT(1:L) TO VAR1
MOVE VAR-INPUT(OFFSET:1) TO VAR2
STRING VAR1 DELIMITED BY SPACE
VAR2 DELIMITED BY SPACE
INTO RESULT
Here's a working example from OpenCobolIDE
IDENTIFICATION DIVISION.
PROGRAM-ID. YOUR-PROGRAM-NAME.
DATA DIVISION.
FILE SECTION.
WORKING-STORAGE SECTION.
01 A PIC X(37).
01 B PIC 9(2).
01 C PIC X(1).
01 D PIC 9(2).
01 E PIC 9(2).
PROCEDURE DIVISION.
ACCEPT A.
INSPECT A TALLYING B FOR CHARACTERS BEFORE SPACE.
MOVE A(B:) TO C.
PERFORM VARYING D FROM B BY -1 UNTIL D = 1
MOVE D TO E
SUBTRACT 1 FROM E
MOVE A(E:1) TO A(D:1)
END-PERFORM.
MOVE C TO A(1:1).
DISPLAY A.
END PROGRAM YOUR-PROGRAM-NAME.
Insert a DISPLAY A inside the PERFORM loop to see how the workflow goes.

COBOL Error Code 18

I have an error code 18 in COBOL when I'm trying to write the output to a file. I'm using Micro Focus VS 2012. I have tried everything but it seem doesn't print the output correctly at this time.
...
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT GRADE-FILE ASSIGN TO 'Grades.txt'.
SELECT PRINT-FILE ASSIGN TO 'Output.txt'
ORGANIZATION IS LINE SEQUENTIAL.
DATA DIVISION.
FILE SECTION.
FD GRADE-FILE
LABEL RECORDS ARE STANDARD.
01 GRADE-RECORD.
05 I-STUDENT PIC X(14).
05 I-GRADE1 PIC 999.
05 I-GRADE2 PIC 999.
05 I-GRADE3 PIC 999.
05 I-GRADE4 PIC 999.
05 I-GRADE5 PIC 999.
05 I-GRADE6 PIC 999.
FD PRINT-FILE
LABEL RECORDS ARE STANDARD.
01 PRINT-RECORD PIC X(80).
WORKING-STORAGE SECTION.
01 PROGRAM-VARIABLES.
05 W-AVERAGE PIC 999V99.
05 W-EOF-FLAG PIC X VALUE 'N'.
01 PAGE-TITLE.
05 PIC X(46) VALUE
' S I X W E E K G R A D E R E P O R T'.
01 HEADING-LINE1.
05 PIC X(51) VALUE
' Student T e s t S c o r e s Average'.
01 HEADING-LINE2.
05 PIC X(51) VALUE
'--------------------------------------------------'.
01 DETAIL-LINE.
05 PIC X VALUE SPACE.
05 O-STUDENT PIC X(14).
05 PIC X VALUE SPACE.
05 O-GRADE1 PIC ZZ9.
05 PIC X VALUE SPACE.
05 O-GRADE2 PIC ZZ9.
05 PIC X VALUE SPACE.
05 O-GRADE3 PIC ZZ9.
05 PIC X VALUE SPACE.
05 O-GRADE4 PIC ZZ9.
05 PIC X VALUE SPACE.
05 O-GRADE5 PIC ZZ9.
05 PIC X VALUE SPACE.
05 O-GRADE6 PIC ZZ9.
05 PIC X(4) VALUE SPACE.
05 O-AVERAGE PIC ZZ9.99.
PROCEDURE DIVISION.
10-MAINLINE.
OPEN INPUT GRADE-FILE
OUTPUT PRINT-FILE
PERFORM 20-PRINT-HEADINGS
PERFORM 30-PROCESS-LOOP
CLOSE GRADE-FILE
PRINT-FILE
STOP RUN.
20-PRINT-HEADINGS.
MOVE PAGE-TITLE TO PRINT-RECORD
WRITE PRINT-RECORD AFTER ADVANCING 1 LINE
MOVE HEADING-LINE1 TO PRINT-RECORD
WRITE PRINT-RECORD AFTER ADVANCING 3 LINES
MOVE HEADING-LINE2 TO PRINT-RECORD
WRITE PRINT-RECORD AFTER ADVANCING 1 LINE.
30-PROCESS-LOOP.
* PERFORM 40-READ-RECORD
READ GRADE-FILE
PERFORM UNTIL W-EOF-FLAG = 'Y'
PERFORM 50-COMPUTE-GRADE-AVERAGE
PERFORM 60-PRINT-DETAIL-LINE
READ GRADE-FILE
* PERFORM 40-READ-RECORD
END-PERFORM.
*40-READ-RECORD.
* READ GRADE-FILE
* AT END MOVE 'Y' TO W-EOF-FLAG.
50-COMPUTE-GRADE-AVERAGE.
COMPUTE W-AVERAGE ROUNDED = (I-GRADE1 + I-GRADE2 + I-GRADE3 + I-GRADE4 + I-GRADE5 + I-GRADE6 ) / 6.
60-PRINT-DETAIL-LINE.
MOVE SPACES TO DETAIL-LINE
MOVE I-STUDENT TO O-STUDENT
MOVE I-GRADE1 TO O-GRADE1
MOVE I-GRADE2 TO O-GRADE2
MOVE I-GRADE3 TO O-GRADE3
MOVE I-GRADE4 TO O-GRADE4
MOVE I-GRADE5 TO O-GRADE5
MOVE I-GRADE6 TO O-GRADE6
MOVE W-AVERAGE TO O-AVERAGE
WRITE PRINT-RECORD FROM DETAIL-LINE AFTER ADVANCING 1 LINE.
end program "GradeReport.Program1"
S I X W E E K G R A D E R E P O R T
Student T e s t S c o r e s Average
--------------------------------------------------
KellyAntonetz0 700 500 980 800 650 852 747.00
obertCain09708 207 907 309 406 2;1 25> 400.67
Dehaven0810870 940 850 930 892 122 981 785.83
rmon0760770800 810 750 92; 142 9>1 <1> 816.33
g0990930890830 940 901 =1> 41= ?82 65 872.50
06707108408809 6=9 ;52 565 <<0 900 870 924.33
78052076089Woo 493 9>4 520 760 760 830 734.50
Something prior to your COBOL program has pickled your file by removing all the spaces and shuffling the data to the left.
Your first student shows as KellyAntonetz but likely should be Kelly Antonetz. Since only one space was removed, the grade data has moved only one place to the left, so the numbers are still recognizable and although the average is a factor of 10 out, it is approximately correct.
It is not actually correct (except for the power of 10) because of that 2 following the 85. Where did that 2 come from?
It came from the next record, where the first-name should be Robert but you show as obertCain09708. The ASCII code for the letter R is X'82'. When treated as a number by COBOL the 8 will be ignored (or will cause a crash when in the trailing byte of a number). Your compiler doesn't cause the code to crash, but does treat the R as the number 2.
obertCain is only 9 bytes out of the 14 you have for the name. The five spaces/blanks which have been "lost" this time cause the numerics to be pulled-left by five bytes. From that point onward, explaining how the output you show fits the presumed input becomes an academic exercise only.
Further support is a reference for what would be a FILE STATUS code of 18 from a Micro Focus compiler, here: http://www.simotime.com/vsmfsk01.htm
Which says, for 18:
Read part record error: EOF before EOR or file open in wrong mode
(Micro Focus).
Your final record would "finish" before expected, with end-of-file being detected before 32 bytes have been read.
Note that the error is on your input file, not your output file.
Losing the spaces in that way can be done in many ways, so I can't guess what you are doing to the file before it gets to the COBOL program, but neither COBOL itself nor your code is doing that.
Take note of Emmad Kareem's comments. Use the FILE STATUS. Check the file-status field (define one per file) after each IO, so that you know when a problem occurs, and what the problem is.
Testing the file-status field for 10 on a file you are reading sequentially gives cleaner code than the AT END on the READ.
Note also that if your program had not crashed there, it would either loop infinitely or crash shortly afterwards. Probably in trying to fix your problem, you have commented-out your use of the "read paragraph" and in that paragraph is the only place you are setting end-of-file.
If you use the file-status instead of AT END, you don't need to define a flag/switch you can use an 88 on the file-status field and have the COBOL run-time set it for you directly, without you having to code it.
Just a couple of points about your DETAIL-LINE.
There is no need to MOVE SPACE to it, as you MOVE to each named field, and the (un-named) FILLERs have VALUE SPACE.
You don't necessarily need the (un-named) FILLERS. Try this:
01 DETAIL-LINE.
05 O-STUDENT PIC BX(14).
05 O-GRADE1 PIC ZZZ9.
05 O-GRADE2 PIC ZZZ9.
05 O-GRADE3 PIC ZZZ9.
05 O-GRADE4 PIC ZZZ9.
05 O-GRADE5 PIC ZZZ9.
05 O-GRADE6 PIC ZZZ9.
05 O-AVERAGE PIC Z(6)9.99.
If you work with COBOL, you may see this type of thing, so it is good to know. With massive amounts of output there is probably a small performance penalty. You may find it more convenient for "lining-up" output to headings.
Ah. Putting together you non-use of LINE SEQUENTIAL for your input file, I predict you have a "script" running some time before the COBOL program which is supposed to remove the record-terminators (whatever those are on your OS) at the end of each logical record, but that you have accidentally removed all whitespace from all positions of your record instead.
With LINE SEQUENTIAL you can have records of fixed-length which also happen to be "terminated". Unless the exercise specifically includes the removal of the record terminators, just use LINE SEQUENTIAL.
If you are supposed to remove the terminators, don't do so for whitespace which covers too much (be specific) and also "anchor" the change to the end of the record.

How can I convert an alphanumeric and use it for calculation?

I will read a sequential file which include some string such as "79.85", "1000", "212.34".
I want to convert the alphanumeric into number in this format 00000.00 ?
I will need to add up these numbers and move it to a field in the format 0000000.00 .
I tried:
01 WS_AMOUNT_TXT PIC X(8).
01 WS_AMOUNT PIC 9(5).9(2).
MOVE WS_AMOUNT_TXT(1:8) TO WS_AMOUNT(1:8).
What I got is unexpected, the string is just as same. It is left align and no leading zero display.
How can I made it right align and have leading zero?
EDIT: I tried the suggestion by NealB, and it sadly failed:
01 WS_AMOUNT_NUM PIC 9(5)V9(2).
01 WS_AMOUNT_DISPLAY PIC 9(5).9(2).
01 WS_AMOUNT_TXT PIC X(8).
DISPLAY WS_AMOUNT_TXT
COMPUTE WS_AMOUNT_NUM = FUNCTION NUMVAL (WS_AMOUNT_TXT)
MOVE WS_AMOUNT_NUM TO WS_AMOUNT_DISPLAY
79.85 << this is what was displayed when I called DISPLAY WS_AMOUNT_TXT
AND THEN IT CRASHED.
%COB-F-NUMVALARGINV, NUMVAL or NUMVAL-C argument invalid
%TRACE-F-TRACEBACK, symbolic stack dump follows
image module routine line rel PC abs PC
DEC$COBRTL 0 000000000001F2B8 000000007C2F72B8
DEC$COBRTL 0 0000000000014764 000000007C2EC764
DEC$COBRTL 0 0000000000014C44 000000007C2ECC44
DAILY_SPLIT_REFUND_ADJ DAILY_SPLIT_REFUND_ADJ DAILY_SPLIT_REFUND_ADJ
121 00000000000003C4 00000000000303C4
DAILY_SPLIT_REFUND_ADJ 0 00000000000313A0 00000000000313A0
0 FFFFFFFF80271EF4 FFFFFFFF80271EF4
Try using the intrinsic function NUMVAL
to do the conversion. Something like...
01 WS-AMOUNT-TEXT PIC X(8).
01 WS-AMOUNT-NUM PIC 9(5)V9(2).
01 WS-AMOUNT-DISPLAY PIC 9(5).9(2).
COMPUTE WS-AMOUNT-NUM = FUNCTION NUMVAL (WS-AMOUNT-TEXT)
MOVE WS-AMOUNT-NUM TO WS-AMOUNT-DISPLAY
NUMVAL converts the text representation of a number into a numeric type. Use the numeric data type: PIC 9(5)V9(2) in your calculations. Then use MOVE
to convert the numeric result into a displayable amount with explicit decimal point.
Note: If you have a lot of calculations to perform, it might be best to use a PACKED-DECIMAL data type to improve efficiency.
Use redefine.
01 WS-AMOUNT-TXT-GRP.
03 WS-AMOUNT PIC X(4).
01 WS-AMOUNT-NUM REDEFINES WS-AMOUNT-TXT-GRP PIC 9(4).
After re=licating value in WS-AMOUNT-TXT-GRP or in WS-AMOUNT, automatically value will replicate in WS-AMOUNT-NUM

Problem with COBOL move to comp-3 variable

I'm having the following problem in a COBOL program running on OpenVMS.
I have the following variable declaration:
01 STRUCT-1.
02 FIELD-A PIC S9(6) COMP-3.
02 FIELD-B PIC S9(8) COMP-3.
01 STRUCT-2.
03 SUB-STRUCT-1.
05 FIELD-A PIC 9(2).
05 FIELD-B PIC 9(4).
03 SUB-STRUCT-2.
05 FIELD-A PIC 9(4).
05 FIELD-B PIC 9(2).
05 FIELD-C PIC 9(2).
And the following code:
* 1st Test:
MOVE 112011 TO FIELD-A OF STRUCT-1
MOVE 20100113 TO FIELD-B OF STRUCT-1
DISPLAY "FIELD-A : " FIELD-A OF STRUCT-1 CONVERSION
DISPLAY "FIELD-B : " FIELD-B OF STRUCT-1 CONVERSION
* 2nd Test:
MOVE 112011 TO SUB-STRUCT-1.
MOVE 20100113 TO SUB-STRUCT-2.
MOVE SUB-STRUCT-1 TO FIELD-A OF STRUCT-1
MOVE SUB-STRUCT-2 TO FIELD-B OF STRUCT-1
DISPLAY "SUB-STRUCT-1 : " SUB-STRUCT-1
DISPLAY "SUB-STRUCT-2 : " SUB-STRUCT-2
DISPLAY "FIELD-A : " FIELD-A OF STRUCT-1 CONVERSION
DISPLAY "FIELD-B : " FIELD-B OF STRUCT-1 CONVERSION
Which outputs:
FIELD-A : 112011
FIELD-B : 20100113
SUB-STRUCT-1 : 112011
SUB-STRUCT-2 : 20100113
FIELD-A : 131323
FIELD-B : 23031303
Why FIELD-A and FIELD-B hold values different from what I move into them in the second test?
I've other moves from DISPLAY to COMP-3 variables in my program where I don't get this behavior.
In COBOL, Group level data are typeless and are moved without casting.
Element level data always have an associated data type. Typed
data are cast to match the type
of the receiving element during a MOVE.
In the first instance you MOVE a literal numeric value (112011) to a packed decimal field and the compiler converts it to the correct data type in the process. Just as you would expect in any programming language.
In the second instance you MOVE a literal value to a group item. Since this is a group item the compiler cannot 'know' the intended data type so it always does group moves as character data (no numeric conversions). This is fine when the receiving item has a PICTURE clause that is compatible with character data - which FIELD-A and FIELD-B
of SUB-STRUCT-1 are. There is no difference in the internal representation of a 9 when stored as PIC X and when stored as PIC 9. Both are assumed USAGE DISPLAY.
Now when you do a group level move from SUB-STRUCT-1 to a COMP-3 (Packed Decimal) you effectively tell the compiler not to convert from DISPLAY to COMP-3 format. And that is what you get.
Try the following modifications to your code. Using REDEFINES creates
a numeric elementary item for the move. COBOL will do the appropriate
data conversions when moving elementary data.
01 STRUCT-2.
03 SUB-STRUCT-1.
05 FIELD-A PIC 9(2).
05 FIELD-B PIC 9(4).
03 SUB-STRUCT-1N REDEFINES
SUB-STRUCT-1 PIC 9(6).
03 SUB-STRUCT-2.
05 FIELD-A PIC 9(4).
05 FIELD-B PIC 9(2).
05 FIELD-C PIC 9(2).
03 SUB-STRUCT-2N REDEFINES
SUB-STRUCT-2 PIC 9(8).
And the following code:
* 3RD TEST:
MOVE 112011 TO SUB-STRUCT-1.
MOVE 20100113 TO SUB-STRUCT-2.
MOVE SUB-STRUCT-1N TO FIELD-A OF STRUCT-1
MOVE SUB-STRUCT-2N TO FIELD-B OF STRUCT-1
DISPLAY "SUB-STRUCT-1 : " SUB-STRUCT-1
DISPLAY "SUB-STRUCT-2 : " SUB-STRUCT-2
DISPLAY "FIELD-A : " FIELD-A OF STRUCT-1
DISPLAY "FIELD-B : " FIELD-B OF STRUCT-1
Beware: Moving character data into a COMP-3 field may give you the dreaded SOC7 data exception abend when the receiving item is referenced. This is because not all bit patterns are valid COMP-3 numbers.
You have 2 Issues.
COBOL has several Numeric Data Structures. Each has its own set of rules.
For PACKED DECIMAL ( COMP-3 )
• The numeric components of the PIC clause should ALWAYS add up to an ODD number.
• The decimal marker “V” determines the placement of the decimal point.
• The individual element MOVE and math functions will maintain the decimal value alignment – both high and low level truncation is possible
• Numeric data type conversion (zone decimal to packed & binary to packed) is handled for you.
e.g. S9(5)V9(2) COMP-3.
including the 2 decimal positions>
Length is calculated as ROUND UP[ (7 + 1) / 2] = 4 bytes
S9(6)V9(2) COMP-3.
including the 2 decimal positions >
Length is calculated as ROUND UP[(8 + 1) / 2] = 5 bytes
But the 1st ½ byte is un-addressable
The last ½ byte of the COMP-3 fields is the HEXIDECIMAL representation of the sign.
The sign ½ byte values are C = signed positive D = signed negative F = unsigned (non COBOL).
S9(6)V9(3) COMP-3 VALUE 123.45.
Length is calculated as ROUND UP[(9 + 1) / 2] = 5 bytes
Contains X’00 01 23 45 0C’
Note the decimal alignment & zero padding.
Group Level MOVE rules
COBOL Data field structures are define as hierarchical structures.
The 01 H-L group field – & any sub-group level field –
Is almost always an implied CHARACTER string value
If an individual element field is a 01 or 77 level – then it can be numeric.
Individual element fields defined as a numeric under a group or sub-group level will be treated as numeric if referenced as an Individual element field.
Numeric rules apply.
o Right justify
o decimal place alignment
o pad H-L (½ bytes) with zeros
o Numeric data type conversion
The receiving field of a MOVE or math calculation determines if a numeric data conversion will occur.
Numeric Data Conversion
If you MOVE or perform a math calculation using any sending field type (group or element) to any receiving individual element field defined using a numeric PIC clause --- then numeric data conversion will occur for the receiving field. S0C7 abends occur when non-numeric data is MOVE ‘d to a receiving numerically defined field OR when math calculations are attempted using non-numeric data.
No Numeric Data Conversion
If you move any field type (group or element) to any group or sub-group level field then there will be NO numeric data conversion.
• Character MOVE rules apply.
• Left Justify & pad with spaces.
This is one of the primary causes of non-numeric data in a numerically defined field.
One of the primary uses of a sending group level MOVE containing numeric element fields to a receiving group level containing numeric element fields (mapped identically) is for re-initializing numeric element fields using 1 MOVE instruction.
A Clear Mask – or – a data propagation MOVE is also possible for table clears - where the table group level is greater than 255 bytes.

Resources