Как отобразить десятичный формат вывода в коболе?

В настоящее время я изучаю старый язык программирования 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 ответа

На первый взгляд я замечаю две проблемы с вашим кодом:

  1. Длина вашего PRINT-LINE а также TRANSFER-LINE отличаются из-за разницы в PICTURE-пункты числовых предметов. Например PRINT-LINE использования PIC ZZ9.99 в то время как TRANSFER-LINE использования PIC 9(3)V99, Обратите внимание, что десятичная точка . в PICTURE-clause требует один байт памяти, в то время как V не занимает никакого хранения вообще, поэтому поле в PRINT-LINE на один байт больше, чем в TRANSFER-LINE,
  2. Когда вы делаете 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.

С ТЕСТОМ ПЕРЕД - по умолчанию. Не нужно указывать это.

Учтите, что поля, которые могут стать отрицательными, не будут делать это, если они не подписаны.

Создайте свою программу, прежде чем писать. Если выясняется, что дизайн не работает, измените дизайн, а не просто "исправьте" существующую программу, чтобы она выглядела так, как будто она "работает".

Например, вы знаете, что вам нужен заголовок для каждой записи, не так ли? Зачем проверять это внутри цикла?

Другие вопросы по тегам