Как отобразить десятичный формат вывода в коболе?
В настоящее время я изучаю старый язык программирования COBOL, но столкнулся с проблемой. это образец программы Cobol.
IDENTIFICATION DIVISION.
PROGRAM-ID. MONTHLY.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT IN-FILE ASSIGN TO "USERINPUT.DAT".
SELECT OUT-FILE ASSIGN TO "USEROUTPUT.DAT".
DATA DIVISION.
FILE SECTION.
FD IN-FILE
LABEL RECORDS ARE STANDARD
DATA RECORD IS IN-REC.
01 IN-REC.
02 C-NAME PIC X(25).
02 STREET PIC X(20).
02 ZIP-CODE PIC X(15).
02 CREDIT PIC 9(6)V99.
02 MONTH PIC 99.
02 FILLER PIC XX VALUE "\n".
FD OUT-FILE
LABEL RECORDS ARE STANDARD
DATA RECORD IS OUT-REC.
01 OUT-REC PIC X(80).
*-----------------------
WORKING-STORAGE SECTION.
*-----------------------
01 HDG-01.
02 FILLER PIC X(27) VALUE SPACES.
02 FILLER PIC X(27) VALUE "ABC Loans & Savings Company".
01 HDG-02.
02 FILLER PIC X(28) VALUE SPACES.
02 FILLER PIC X(25) VALUE "Ayala Avenue, Makati City".
01 HDG-03.
02 FILLER PIC X(30) VALUE SPACES.
02 FILLER PIC X(20) VALUE "SCHEDULE OF PAYMENTS".
01 HDG-04.
02 FILLER PIC X(28) VALUE SPACES.
02 FILLER PIC X(15) VALUE "ORIGINAL AMOUNT".
02 REC-CREDIT PIC Z(5)9.99.
01 HDG-05.
02 FILLER PIC X(14) VALUE SPACES.
02 FILLER PIC X(9) VALUE "MONTH".
02 FILLER PIC X(11) VALUE "INTEREST".
02 FILLER PIC X(17) VALUE "TOTAL-PAYMENT".
02 FILLER PIC X(14) VALUE "UNPAID-BALANCE".
01 TRANSFER-LINE.
02 FILLER PIC X(16) VALUE SPACES.
02 REC-MONTH PIC 99.
02 FILLER PIC X(6) VALUE SPACES.
02 INTEREST PIC 9(3)V99.
02 FILLER PIC X(7) VALUE SPACES.
02 TOTAL-PAY PIC 9(6)v99.
02 FILLER PIC X(10) VALUE SPACES.
02 UNPAID-BAL PIC 9(6)v99.
01 PRINT-LINE.
02 FILLER PIC X(16) VALUE SPACES.
02 FILLER PIC 99.
02 FILLER PIC X(6) VALUE SPACES.
02 FILLER PIC ZZ9.99.
02 FILLER PIC X(7) VALUE SPACES.
02 FILLER PIC Z(5)9.99.
02 FILLER PIC X(10) VALUE SPACES.
02 FILLER PIC Z(5)9.99.
01 PRINT-NULL.
02 FILLER PIC X(16) VALUE SPACES.
02 FILLER PIC XX VALUE "--".
02 FILLER PIC X(6) VALUE SPACES.
02 FILLER PIC XXXXX VALUE "-----".
02 FILLER PIC X(7) VALUE SPACES.
02 FILLER PIC X(9) VALUE "---------".
02 FILLER PIC X(9) VALUE SPACES.
02 FILLER PIC X(9) VALUE "---------".
01 X PIC 99.
01 REM PIC 999.
01 CHECK-MONTH PIC 99.
01 CLIENT-NO PIC 9.
01 PRINT-ASTERISK.
02 FILLER PIC X(30) VALUES ALL "*" .
02 FILLER PIC X(18) VALUES "-END OF CLIENT NO ".
02 CLIENT PIC 9.
02 FILLER PIC X VALUE "-".
02 FILLER PIC X(30) VALUES ALL "*" .
PROCEDURE DIVISION.
OPEN INPUT IN-FILE
OUTPUT OUT-FILE.
REPEAT-RTN.
ADD 1 TO CLIENT-NO.
MOVE CLIENT-NO TO CLIENT.
READ IN-FILE AT END PERFORM CLOSE-RTN.
MOVE CREDIT TO UNPAID-BAL.
MOVE MONTH TO CHECK-MONTH.
PERFORM WITH TEST BEFORE UNTIL CHECK-MONTH < 13
COMPUTE CHECK-MONTH = CHECK-MONTH - 12
END-PERFORM.
COMPUTE CHECK-MONTH = MONTH + (12 - CHECK-MONTH).
MOVE ZEROES TO X.
PERFORM PROCESS-RTN CHECK-MONTH TIMES.
WRITE OUT-REC FROM PRINT-ASTERISK AFTER 1 LINE.
PERFORM REPEAT-RTN.
PROCESS-RTN.
ADD 1 TO X.
MOVE X TO REM.
PERFORM WITH TEST BEFORE UNTIL REM <= 13
COMPUTE REM = REM - 12
END-PERFORM.
IF REM=13 OR REM = 1 THEN
PERFORM HDG-RTN
END-IF.
IF REM=13 THEN
MOVE SPACES TO OUT-REC
WRITE OUT-REC.
MOVE X TO REC-MONTH.
COMPUTE INTEREST = UNPAID-BAL * 0.015.
COMPUTE TOTAL-PAY ROUNDED= CREDIT / MONTH + INTEREST.
COMPUTE UNPAID-BAL = UNPAID-BAL - TOTAL-PAY + INTEREST.
IF UNPAID-BAL < 1 THEN
MOVE ZEROES TO UNPAID-BAL
END-IF.
IF X > MONTH THEN
WRITE OUT-REC FROM PRINT-NULL AFTER 1 LINE
ELSE
MOVE TRANSFER-LINE TO PRINT-LINE
WRITE OUT-REC FROM PRINT-LINE AFTER 1 LINE
END-IF.
HDG-RTN.
IF X > 1 THEN
WRITE OUT-REC FROM HDG-01 AFTER 2 LINE
WRITE OUT-REC FROM HDG-02 AFTER 1 LINE
WRITE OUT-REC FROM C-NAME AFTER 2 LINE
ELSE IF CLIENT-NO > 1 THEN
WRITE OUT-REC FROM HDG-01 AFTER 1 LINE
WRITE OUT-REC FROM HDG-02 AFTER 1 LINE
WRITE OUT-REC FROM C-NAME AFTER 2 LINE
ELSE
WRITE OUT-REC FROM HDG-01 BEFORE 1 LINE
WRITE OUT-REC FROM HDG-02 BEFORE 1 LINE
WRITE OUT-REC FROM C-NAME AFTER 1 LINE
END-IF.
WRITE OUT-REC FROM STREET AFTER 1 LINE.
WRITE OUT-REC FROM ZIP-CODE AFTER 1 LINES.
WRITE OUT-REC FROM HDG-03 AFTER 2 LINE.
MOVE CREDIT TO REC-CREDIT.
WRITE OUT-REC FROM HDG-04 AFTER 1 LINE.
WRITE OUT-REC FROM HDG-05 AFTER 2 LINE.
CLOSE-RTN.
CLOSE IN-FILE , OUT-FILE.
STOP RUN.
END PROGRAM MONTHLY.
Предполагается, что программа выдаст такой результат:
ABC Loans & Savings Company
Ayala Avenue, Makati City
The Client Name is Here:
The Client Address:
The ZiP/CITY:
SCHEDULE OF PAYMENTS
ORIGINAL AMOUNT 4291.50
MONTH INTEREST TOTAL-PAYMENT UNPAID-BALANCE
01 64.37 422.00 3933.87
02 05900 416.63 3576.24
03 05364 411.27 3218.61
04 04827 405.90 2860.98
05 04291 400.54 2503.35
06 03755 395.18 2145.72
07 03218 389.81 1788.09
08 02682 384.45 1430.46
09 02145 379.08 1072.83
10 01609 373.72 715.20
11 01072 368.35 357.57
12 00536 362.99 0.00
******************************-END OF CLIENT NO 1-******************************
Но вывод программы при запуске программы отличается. Это выглядит так:
ABC Loans & Savings Company
Ayala Avenue, Makati City
The Client Name is Here:
The Client Address:
The ZiP/CITY:
SCHEDULE OF PAYMENTS
ORIGINAL AMOUNT 4291.50
MONTH INTEREST TOTAL-PAYMENT UNPAID-BALANCE
01 06437 00042200 00393387
02 05900 00041663 00357624
03 05364 00041127 00321861
04 04827 00040590 00286098
05 04291 00040054 00250335
06 03755 00039518 00214572
07 03218 00038981 00178809
08 02682 00038445 00143046
09 02145 00037908 00107283
10 01609 00037372 00071520
11 01072 00036835 00035757
12 00536 00036299 00000000
******************************-END OF CLIENT NO 1-******************************
У меня проблема с десятичным форматированием и нулевым подавлением. Какой совет? кстати, я просто использовал файл DAT для ввода, поэтому я не использую ACCEPT или функции ввода, и он содержит точный символ, необходимый для записи, такой как текст ниже:
Имя клиента здесь: Адрес клиента: ZiP/CITY: 0042915012
Я считаю, что проблема заключается в рабочем хранилище печатной линии и линии передачи.
2 ответа
На первый взгляд я замечаю две проблемы с вашим кодом:
- Длина вашего
PRINT-LINE
а такжеTRANSFER-LINE
отличаются из-за разницы вPICTURE
-пункты числовых предметов. НапримерPRINT-LINE
использованияPIC ZZ9.99
в то время какTRANSFER-LINE
использованияPIC 9(3)V99
, Обратите внимание, что десятичная точка.
вPICTURE
-clause требует один байт памяти, в то время какV
не занимает никакого хранения вообще, поэтому поле вPRINT-LINE
на один байт больше, чем вTRANSFER-LINE
, - Когда вы делаете
MOVE TRANSFER-LINE TO PRINT-LINE
вы не выполняете передачу по полю, а вместо этого перемещаете весь блок данных как единое целое, поэтомуPICTURE
-классы вPRINT-LINE
полностью игнорируются. Вы не столкнетесь с большими проблемами, так какPRINT-LINE
занимает больше памяти, чемTRANSFER-LINE
(см. 1.) - если бы это было наоборот, у вас могли бы быть проблемы с перезаписью хранилища (но, по крайней мере, вы должны получить предупреждение компилятора).
Чтобы получить это право, вы могли бы
- Назовите предметы уровня 02
PRINT-LINE
как те изTRANSFER-LINE
и сделатьMOVE CORRESPONDING TRANSFER-LINE TO PRINT-LINE
- но тогда вам придется обратиться к вашему полю с квалифицированным именем (INTEREST OF TRANSFER-LINE
)
или же
- Избавляться от
TRANSFER-LINE
и поместите ваши данные непосредственно вPRINT-LINE
@piet.t указал на проблему при создании вашего вывода. Только когда отдельное поле является целевым полем для чего-либо, произойдет любое преобразование данных любого типа. При перемещении группы в группу все подчиненные определения игнорируются.
В дальнейшем:
У вас есть "рекурсивное" использование PERFORM. То, что это делает, не определено и может отличаться от компилятора к компилятору. Никогда не используйте это.
У вас есть предложение VALUE для элемента не 88-го уровня в РАЗДЕЛЕ ФАЙЛА. Это ничего не делает - и если это было сделано, что вы пытались?
Ваше наименование плохое. Программы COBOL часто существуют много-много лет. Некоторые программы, написанные в 1970-х годах, до сих пор работают со 100-й точностью. Программа будет написана один раз, но ее нужно будет понимать много раз, поэтому пишите, чтобы люди ее поняли. Не используйте имена из одного слова, используйте описательные имена (всегда есть вероятность, что новый стандарт COBOL "зарезервирует" ваше имя из одного слова, и это приведет к путанице в следующий раз, когда программа изменится). X, REM и CHECK-MONTH означают что? Что означает МЕСЯЦ (а не то, что люди ожидают)?
Что это, и это двоюродный брат, должен делать?
PERFORM WITH TEST BEFORE UNTIL CHECK-MONTH < 13
COMPUTE CHECK-MONTH = CHECK-MONTH - 12
END-PERFORM.
Для кого-то, обеспокоенного "древними" языками, почему вы печатаете все эти точки / периоды? Они не нужны в таком широком (и подверженном ошибкам) использовании с 1985 года.
Используйте END-IF. Всегда, а не только тогда, когда вам хочется, заканчивать каждый ЕСЛИ.
Используйте ОЦЕНИТЬ. Выпускается с 1985 года и заменяет вложенный IF-дефицит END-IF.
С ТЕСТОМ ПЕРЕД - по умолчанию. Не нужно указывать это.
Учтите, что поля, которые могут стать отрицательными, не будут делать это, если они не подписаны.
Создайте свою программу, прежде чем писать. Если выясняется, что дизайн не работает, измените дизайн, а не просто "исправьте" существующую программу, чтобы она выглядела так, как будто она "работает".
Например, вы знаете, что вам нужен заголовок для каждой записи, не так ли? Зачем проверять это внутри цикла?