Return to Stories
A Sitting Duck
by Keith Falkner

When I was a very green programmer, I overheard some more experienced programmers discussing a very slow card-to-tape program. It had been written in 1401 COBOL, the compiler for which produced notoriously slow, bulky, and inefficient code. It turned out that the critically slow code was a look-up process. Columns 21-23 of each card contained a 3-digit code that determined whether the amount of money in columns 31-38 was a credit to be treated as positive or a debit to be treated as negative.

A deck of table-cards defined which digits meant credit and which meant debit, so the program had a table of 1000 3-digit numbers. Logic searched this table sequentially for each card, and the program read 79 cards per minute, almost one tenth the rated speed of the 1402 card reader. Someone coded a binary search in place of the sequential search, and begorrah the speed went up to 120 cards per minute. Someone else looked at the data and discovered which 3-digit codes were the most popular, and used a non-sequenced table, in which the most popular codes were at the front. This didn't raise the speed much. Eventually, the most popular codes were hard-coded in the program, and then the program chose one of three tables to search, one for codes under 200, one for codes between 201 and 400, and one for the higher numbers. I think the speed went up to 200 CPM, and the program put some 400 boxes of cards onto tape, taking more than 70 man-hours to do it.

And what is that QUACKING noise I have been hearing all the time I told this tale?

It comes from a sitting duck. This situation does not require three thousand bytes for a table, and it does not require any lookup at all!. It just requires a table with one thousand bits, but because the 1401 is not made to handle individual bits practically, we use 1000 bytes. Then the numeric value in columns 21-23 is used as the index!

Here is the solution in COBOL:

in the input card:


    05  COL-21-23     PICTURE 999.
    05  FILLER REDEFINES COL-21-23.
    09  COL-21    PICTURE X.
    09  COL-22    PICTURE X.
    09  COL-23    PICTURE X.

 WORKING-STORAGE SECTION. 
    01  CREDIT-DEBIT-TABLE. 
    05  CDT-ARRAY. 
    09  CDT-BYTE  PICTURE X  OCCURS 1000 TIMES. 
    05  CDT-INDEX     PICTURE 9999. 

In initialization, we first

MOVE ALL 'C' TO CDT-ARRAY.

then we read some table-cards bearing ranges of 3-digit numbers defining the codes in columns 21-23 that mean DEBIT, and move 'D' to each corresponding CDT-BYTE.

And each card is tested thus


IF COL-21 LESS '0'
OR COL-22 LESS '0'
OR COL-23 LESS '0'
    MOVE 'NON-NUMERIC CREDIT-DEBIT-CODE' TO ERR-TEXT
    GO TO BAD-CARD-LOGIC.
MOVE COL-21-23 TO CDT-INDEX
IF CDT-BYTE (CDT-INDEX) = 'C'
    (treat money as credit)
ELSE
    (treat money as debit).

It's lots easier in Autocoder:

   CDTBYT  DCW  0
   CDTLAS  DS   999
 
 To fill the table, 
    MCW  @C@,CDTLAS
    MCW  CDTLAS  THIS FILLS 999 BYTES.
 
 To store a D somewhere
    MCW  DEBCOD,X1
    MCW  @D@,CDTBYT&X1
 
 To check a card:
 * MAKE SURE COL 21-23 CONTAIN NUMERIC DATA.
    C    21,@0@
    BH   BADCODE
    C    22,@0@
    BH   BADCODE
    C    23,@0@
    BH   BADCODE
 *  USE CODE TO FIND IF MONEY IS CR OR DB.
    MCW  23,X1
    BCE  USEDEB,CDTBYT&X1,D

I do not know why those experienced programmers, all of whom were earning much more that I was, failed to spot that sitting duck. In my opinion, the duck was squatting comfortably in the mouth of a cannon, and eventually flew away unscathed!