При выполнении код не будет выполнять математику после отображения строки. (Кобол 85)

Делать график амортизации. Я установил его в модуле 300-REPORT, чтобы отобразить строку с информацией о платеже, а затем после отображения обновить эту информацию, как если бы был произведен другой платеж. Предполагается, что он остановится на балансе $0, а затем запишет все это в текстовый файл.

Проблема в том, что он отображает строку, и вместо новой математики он просто отображает одну и ту же строку снова и снова, создавая таким образом бесконечный цикл.

300-REPORT.
      MOVE WS-BEGYEAR      TO WS-REP-YEAR
      MOVE WS-BEGMONTH     TO WS-REP-MO
      MOVE WS-PRINCIPAL    TO WS-REP-PRIN
      MOVE WS-INTEREST     TO WS-REP-INT                         
      MOVE WS-TERM         TO WS-REP-TERM

      COMPUTE WS-REP-BEG-BAL-M = WS-PRINCIPAL * (1+WS-INT-DEC)
      MOVE WS-REP-BEG-BAL-M   TO WS-REP-BEG-BAL
      MOVE WS-PRINCIPAL    TO WS-REP-BEG-BAL-M

      MOVE WS-PAYMENT-TOT  TO WS-REP-PAYMENT

      COMPUTE WS-INT-PAID-M = WS-PRINCIPAL * WS-INT-DEC
      MOVE WS-INT-PAID-M   TO WS-INT-PAID

      COMPUTE WS-CUR-PRIN-M                                                                                               
          = WS-PRINCIPAL - (WS-PAYMENT-TOT - WS-INT-PAID-M)                  
      MOVE WS-CUR-PRIN-M   TO WS-CUR-PRIN

      COMPUTE WS-END-BAL-M = WS-REP-BEG-BAL-M - WS-PAYMENT-TOT
      MOVE WS-END-BAL-M   TO WS-END-BAL

      WRITE OF-LINE       FROM WS-TITLE3
      WRITE OF-LINE       FROM WS-TITLE4
      WRITE OF-LINE       FROM WS-LINE
      WRITE OF-LINE       FROM WS-PRIN-LINE
      WRITE OF-LINE       FROM WS-INT-LINE
      WRITE OF-LINE       FROM WS-TERM-LINE
      WRITE OF-LINE       FROM WS-LINE
      WRITE OF-LINE       FROM WS-HEADERS
      WRITE OF-LINE       FROM WS-HEADER-SEP.

      PERFORM UNTIL WS-END-BAL-M IS <= 0

          WRITE OF-LINE        FROM WS-REP-DATA-LINE
          DISPLAY WS-REP-DATA-LINE
          ADD 1 TO WS-PMT-NUM
          ADD 1 TO WS-REP-MO
          IF WS-REP-MO = 13
             ADD 1   TO WS-REP-YEAR         
             MOVE 01 TO WS-REP-MO                          
          END-IF
          MOVE WS-END-BAL TO WS-REP-BEG-BAL

          COMPUTE WS-INT-PAID-M = WS-REP-BEG-BAL-M * WS-INT-DEC
          MOVE WS-INT-PAID-M  TO WS-INT-PAID

          COMPUTE WS-CUR-PRIN-M = 
          WS-REP-BEG-BAL-M - (WS-PAYMENT-TOT - WS-INT-PAID-M)
          MOVE WS-CUR-PRIN-M  TO WS-CUR-PRIN

          COMPUTE WS-END-BAL-M = WS-REP-BEG-BAL-M - WS-PAYMENT-TOT
          MOVE WS-END-BAL-M   TO WS-END-BAL

      END-PERFORM        

2 ответа

Ваша проблема (возможно, не единственная) здесь:

COMPUTE WS-END-BAL-M = WS-REP-BEG-BAL-M - WS-PAYMENT-TOT

Ни WS-REP-BEG-BAL-M, ни WS-PAYMENT-TOT не изменяются в цикле, поэтому ответ всегда будет одинаковым, и цикл никогда не прекратится.

Вы можете сделать вещи проще для себя, назвав их лучше, обращая внимание на то, как они кодируются, и используя вещи, которые более естественно отражают то, что вы делаете. Например:

  COMPUTE WS-REP-BEG-BAL-M = WS-PRINCIPAL * (1+WS-INT-DEC)
  MOVE WS-REP-BEG-BAL-M   TO WS-REP-BEG-BAL
  MOVE WS-PRINCIPAL    TO WS-REP-BEG-BAL-M

Лучше как

  COMPUTE WS-REP-BEG-BAL = WS-PRINCIPAL * ( 1 + WS-INT-DEC)
  MOVE WS-PRINCIPAL    TO WS-REP-BEG-BAL-M

Это очень похожее название, и читатель не имеет полного представления о том, что к чему:

WS-END-BAL-M 
WS-REP-BEG-BAL-M 
WS-REP-BEG-BAL
WS-END-BAL

Особенно, когда вы делаете такие вещи:

MOVE WS-END-BAL TO WS-REP-BEG-BAL

Также:

SUBTRACT this-monthly-amount FROM outstanding-amount

Проще понять, какова его цель, чем:

COMPUTE this-monthly-amount = this-monthly-amount - outstanding-amount

Особенно когда разбросаны среди COMPUTEделает другие вещи.

Объедините все вышеперечисленное, и у вас будет фрагмент кода, который очень сложно понять с первого взгляда.

"Кратчайший код для воспроизведения" имеет две цели: во-первых, вы можете сами найти проблему, делая это; во-вторых, это помогает всем, кто смотрит на проблему.

У вас есть большой жирный цикл, поэтому важно условие, которое контролирует цикл. Удалите все, кроме того, что влияет на начальное значение и как его значение изменяется. Важно также включить определения данных. Иногда у вас будет что-то, что нужно подписать, но это не так.

WS-PAYMENT-TOT не является целевым полем в 300-REPORT. Его стоимость определяется в другом месте. Как было отмечено в комментариях @Julien Mousset, если это когда-либо равно нулю, и это все, что когда-либо влияет на ваш декремент в цикле, то у вас будет еще один Big Fat Loop. Таким образом, нам нужно увидеть определение, и где установлен WS-PAYMENT-TOT, и зависит ли то, что PERFORM of 300-REPORT зависит от того, является ли он ненулевым.

Аналогично WS-PRINCIPAL, который является источником WS-REP-BEG-BAL-M.

Теперь уберите все, что не связано с управлением циклом.

300-REPORT.

      MOVE WS-PRINCIPAL    TO WS-REP-BEG-BAL-M

      COMPUTE WS-END-BAL-M = WS-REP-BEG-BAL-M - WS-PAYMENT-TOT

      PERFORM UNTIL WS-END-BAL-M IS <= 0

          DISPLAY "Here we are in BFL"

          COMPUTE WS-END-BAL-M = WS-REP-BEG-BAL-M - WS-PAYMENT-TOT

      END-PERFORM   

Мы можем даже нормализовать это, чтобы использовать WS-PRINCIPAL вместо WS-REP-BEG-BAL-M.

300-REPORT.

      COMPUTE WS-END-BAL-M = WS-PRINCIPAL - WS-PAYMENT-TOT

      PERFORM UNTIL WS-END-BAL-M IS <= 0

          DISPLAY "Here we are in BFL"

          COMPUTE WS-END-BAL-M = WS-PRINCIPAL - WS-PAYMENT-TOT

      END-PERFORM   

При создании "кратчайшего кода для воспроизведения" вы можете видеть, что вычисление в цикле является вычислением для начального значения цикла. Если WS-PRINCIPAL должен быть равен нулю, цикл никогда не будет введен. Если WS-PRINCIPAL = WS-PAYMENT-TOT, цикл никогда не будет введен. Для всех остальных ситуаций цикл будет BFL.

У вас также есть ваша структура в обратном направлении.

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

Сначала напишите все строки.

В вашем цикле выполните всю работу для последующих подробных строк (если они есть) и запишите это как последнюю вещь в цикле.

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

Что-то вроде этого:

      ADD 1 TO WS-REP-MO
      IF WS-REP-MO = 13
         ADD 1   TO WS-REP-YEAR         
         MOVE 01 TO WS-REP-MO                          
      END-IF

Лучше как:

      IF WS-REP-MO = 12
         ADD 1   TO WS-REP-YEAR         
         MOVE 1  TO WS-REP-MO                          
      ELSE
         ADD 1   TO WS-REP-MO
      END-IF

Теперь WS-REP-MO никогда не становится логически недействительным.

Еще лучше, с 88 на WS-REP-MO:

      IF WS-REP-PREV-MONTH-WAS-DECEMBER
          ADD 1   TO WS-REP-YEAR         
          MOVE 1  TO WS-REP-MO                          
      ELSE
          ADD 1   TO WS-REP-MO
      END-IF

Теперь более очевидно, что вы делаете и почему.

Если у вас есть такой же код, поместите его в абзац (или РАЗДЕЛ, если вы его используете) и ВЫПОЛНИТЕ его. Когда код необходимо изменить, у вас есть только одно место, чтобы изменить его. Дайте параграфу хорошее имя, и вы сможете начать "читать" программу.

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

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

Мы привыкли создавать программы с карандашом и бумагой (обычно на обороте старого списка программ), мы прорабатывали дизайн с карандашом, бумагой и мозгом. Затем перенесите дизайн в "скелетную" программу, которая делает основы того, что мы хотели. Добавьте детали, от высокого до низкого. На каждом этапе мы проводим "контрольную проверку", что означает, что вы снова просматриваете код, карандаш, бумагу и мозг.

Затем вы используете компилятор, чтобы определить опечатки. Исправьте это. Получить чистую компиляцию, и вы уже сделали много вещей, чтобы ваша программа работала.

Делая это, вы пропустите эти "о крысы!" моменты, когда вы обнаружите после написания кода, что вам нужно внести серьезные изменения.

С опытом, вы можете сделать все это в своей голове.

В эти дни вы сидите перед компьютером. Я все еще рекомендую маршрут "бумага и карандаш", даже если вы реализуете его с использованием своего ПК.

Если вы просто сядете и напишите программу на языке COBOL, а затем исправите ее, если тестирование не пройдено, результаты никому не будут полезны.

Теперь я вижу, что вы разместили всю программу изначально.

Вы ВЫПОЛНЯЕТЕ 100- из 100- Это нехорошо, даже если вы избежите получения другого BFL (зависит от компилятора).

Вы берете данные с экрана, набранного человеком. Вы должны это проверить.

Использование макета свободного формата не исключает возможности помочь себе и кому-либо еще с помощью отступов.

При тестировании вы должны очень стараться сломать программу. В противном случае ваш пользователь сломает его в первый раз.

Вы не показываете свою логику управления, которая вызывает 300-REPORT, но в зависимости от того, как вы это сделали, ваш случайный период может вызвать неожиданное поведение. Вы могли бы хотеть взять это:

WRITE OF-LINE       FROM WS-HEADER-SEP.

Не уверен, что это вызовет проблемы, но может. Как правило, вам нужны только точки после меток и в самом конце абзаца в коде Cobol-85+.

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