COBOL and $ 2,020 202.02

In past years, even in the last year or two, I sometimes came across the news that someone received an invoice or check for a ridiculous amount of 2,020,202 dollars ... and 02 cents.



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-amountclearly 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-amountnot 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-datarecwill 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!



All Articles