При выполнении код не будет выполнять математику после отображения строки. (Кобол 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+.