COBOL и $2 020 202,02

Автор оригинала: Big Dan the Blogging Man

  • Перевод

В прошлые годы, даже в последние год-два мне иногда попадались новости, что кому-то пришел счёт или чек на смешную сумму 2 020 202 доллара… и 02 цента.

Если вы такое увидите, то (почти наверняка) это ошибка программирования на COBOL. Большинство программистов COBOL совершают эту глупую ошибку, и я не исключение.

проблема вызвана тем, как именно мы обычно инициализируем запись. Возьмём такую маленькую программу:

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.
В этой программе входная запись dr-datarec. Обычно она идет откуда-то с диска, но для этого простого теста создаётся вручную.

Как только получена входная запись, выполняются вычисления, а затем запись выводится с помощью dt-detail.

проблема в том, как создаётся запись dr-datarec. Обратите внимание, как перемещаются пробелы для её инициализации. Это был типичный метод инициализации записи.

Таким образом, пробелы есть во всех полях PIC X. Но! Все поля COMP-3 также инициализируются, только не до нуля. Программист должен быть уверен, что для всех полей COMP-3 создаются допустимые значения. В тестовой программе это делается правильно:

move spaces to dr-datarec.
move "test" to dr-name.
move 100 to dr-amount.
В поле dr-amount явно есть 100. После запуска получается:

./mistake
test 100.00
Что делать, если допущена ошибка кодирования и запись dr-amount не инициализирована должным образом?

Там всё ещё есть пробелы ASCII. Это шестнадцатеричное значение 20 или двоичное 0010 0000.

COMP-3 хранит цифры в виде четырёхбитных «нибблов», поэтому один пробел отображается как 20. Если у вас 9 цифр, как у dr-amount, то для этого требуется 10 нибблов памяти (9 нибблов для цифр и один для знака) или 5 байт.

Перемещение пробелов в dr-datarec приведёт к тому, что в это поле сохранится 5 пробелов или шестнадцатеричное Теперь при запуске программы:

./mistake
test 2,020,202.02
Чтобы исправить эту проблему, COBOL 85 ввёл глагол INITIALIZE. Вместо перемещения пробелов в запись вы её инициализируете, а она переместит пробелы в буквенно-цифровые поля, а нули — в числовые:

* move spaces to dr-datarec.
initialize dt-detail.
move "test" to dr-name.
* move 100 to dr-amount.
Результат выполнения:

./mistake
test 0.00
Так что в следующий раз, когда увидите бедную вдову, которой пришел счёт за коммунальные услуги $2 020 202,02, вы будете точно знать, что произошло!

Источник