If you see this, it is (almost certainly) a COBOL programming error. Most COBOL programmers make this stupid mistake, and I am no exception.
The problem is caused by the way we usually initialize the record. Let's take a small program like this:
identification division.
program-id.
mistake.
data division.
working-storage section.
* *** Input record, typically maintained on disk/tape somewhere.
01 dr-datarec.
03 dr-name pic x(20).
03 dr-amount pic s9(7)v99, comp-3.
* *** print record, sent to a line printer.
01 dt-detail.
03 dt-name pic x(20).
03 filler pic x.
03 dt-amount pic z,zzz,zz9.99.
procedure division.
move spaces to dr-datarec.
move "test" to dr-name.
move 100 to dr-amount.
move spaces to dt-detail.
move dr-name to dt-name.
move dr-amount to dt-amount.
display dt-detail.
stop run.
In this program, the input record
dr-datarec
. Usually it comes from somewhere on disk, but for this simple test it is created manually.
Once an input record is received, the computation is performed, and then the record is output using
dt-detail
.
The problem is how the record is created
dr-datarec
. Notice how the spaces are moved to initialize it. This was the typical method for initializing a record.
Thus, there are spaces in all PIC X fields. But! All COMP-3 fields are also initialized, but not to zero. The programmer must be sure that valid values ββare generated for all COMP-3 fields. The test program does it right:
move spaces to dr-datarec.
move "test" to dr-name.
move 100 to dr-amount.
There is
dr-amount
clearly 100 in the field. After starting it turns out:
./mistake
test 100.00
What if there is an encoding error and the record is
dr-amount
not initialized properly?
There are still ASCII spaces in there. This is a hexadecimal value of 20 or binary 0010 0000.
COMP-3 stores digits as four-bit nibbles, so one space is displayed as 20. If you have 9 digits like dr-amount, then this requires 10 memory nibbles (9 nibbles for digits and one for sign) or 5 bytes.
Moving spaces in
dr-datarec
will result in 5 spaces or the hexadecimal value 2020202020 being stored in this field. If you try to use an uninitialized variable, it will be interpreted as 2020 202.02.
If you comment out the initialization
dr-amount
, you can force this error:
move spaces to dr-datarec.
move "test" to dr-name.
* move 100 to dr-amount.
Now when starting the program:
./mistake
test 2,020,202.02
To correct this problem, COBOL 85 introduced the INITIALIZE verb. Instead of moving spaces into a record, you initialize it, and it moves spaces to alphanumeric fields and zeros to numeric fields:
* move spaces to dr-datarec.
initialize dt-detail.
move "test" to dr-name.
* move 100 to dr-amount.
Execution result:
./mistake
test 0.00
So the next time you see a poor widow who got a $ 2,020,202.02 utility bill, you'll know exactly what happened!