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

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

Я считаю, что проблема заключается в рабочей линии печати и передачи памяти.


person programmer wannabe    schedule 24.08.2016    source источник
comment
Похоже, ваша выборка тоже неверна, если только у вас нет объяснения столбцу процентов.   -  person Bill Woodger    schedule 24.08.2016


Ответы (2)


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

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

or

  • Избавьтесь от TRANSFER-LINE и поместите свои данные прямо в PRINT-LINE
person piet.t    schedule 24.08.2016

@piet.t указал на проблему при создании вашего вывода. Только когда отдельное поле является «целевым» полем для чего-либо, может иметь место любое преобразование данных любого типа. При ПЕРЕМЕЩЕНИИ группы в группу все подчиненные определения игнорируются.

Дальше:

У вас есть «рекурсивное» использование PERFORM. То, что это делает, не определено и может отличаться от компилятора к компилятору. Никогда не используйте это.

У вас есть предложение VALUE для элемента уровня не 88 в FILE SECTION. Это ничего не делает - и если да, то что вы пытались?

Ваше имя неудачное. Программы 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.

WITH TEST BEFORE используется по умолчанию. Нет необходимости указывать это.

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

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

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

person Bill Woodger    schedule 25.08.2016
comment
Я предполагаю, что ЗНАЧЕНИЕ здесь для информационных целей (кажется, возврат каретки, кстати). Но я согласен с вами: хотя рекурсия в некоторых языках сексуальна, в COBOL это не очень хорошая идея. Вообще. И это делается с выходом, который прерывает поток выполнения, так что это даже не правильная рекурсия. Однако даже правильная рекурсия не должна использоваться, как вы сказали. И эта переменная с именем X. Aaaaargh. - person gazzz0x2z; 25.08.2016
comment
@ gazzz0x2z Я знаю, для чего предназначен /n, но COBOL - это компилируемый язык, текст /n во время выполнения - это именно то, что нужно. Текст :-) - person Bill Woodger; 25.08.2016