进行摊销计划。我将它设置在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
答案 0 :(得分:1)
你的问题(也许不是唯一一个)就在这里:
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
做其他事情时散布。
结合上述所有内容,您会看到一段难以理解的代码。
&#34;最短的代码来重现&#34;有两个意图:首先,你可以在做的时候自己发现问题;其次,它有助于其他任何人看到这个问题。
你有一个大脂肪循环,所以重要的是控制循环的条件。删除除影响起始值以及如何修改值的内容之外的所有内容。重要的是还要包括数据定义。有时你会有一些需要签名的东西,但不是。
WS-PAYMENT-TOT不是300-REPORT中的目标字段。其价值在别处确定。正如@Julien Mousset在评论中指出的那样,如果它永远为零,那就是所有这一切都会影响你在循环中的减少,那么你将会有另一个Big Fat Loop。因此,我们需要查看定义,设置WS-PAYMENT-TOT的位置,以及300-REPORT的PERFORM是否以非零为条件。
与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
制作&#34;最短的代码来重现&#34;你可以看到循环内的计算是循环初始值的计算。如果WS-PRINCIPAL为零,则永远不会输入循环。如果WS-PRINCIPAL = WS-PAYMENT-TOT,则永远不会输入循环。对于所有其他情况,循环将是BFL。
你的结构也向后倾斜。
为下次&#34;设置事情并不是一个好主意。这意味着您正在做不必要的工作,使读者感到困惑,并且难以维护程序,因为不清楚字段何时可以安全地更改字段。
先写出所有的行。
在你的循环中,为后续的细节线做所有的工作(如果有的话)并将它写出来作为循环中的最后一件事。
你没有&#34;分页&#34;逻辑。如果你的细节线上有多个行数,它看起来会很难看,即使只有一个&#34;无论什么&#34;每次执行程序时都会打印出来。
这样的事情:
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从未在逻辑上失效。
更好的是,在WS-REP-MO上使用88:
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
现在更明显的是你在做什么,为什么。
如果您的代码相同,请将其放在段落中(如果您使用的话,则将其置于SECTION中)并执行此操作。当代码需要更改时,您只有一个地方可以更改它。给段落一个好名字,你可以开始阅读&#34;该程序。
你很可能是COBOL的初学者。如果你只是修补它&#34;当你走的时候,你最终会得到一个难以理解,难以维护的可怕程序。
不要害怕重新开始。如果可能的话,从一个良好的工作程序开始,该程序会生成一个报告并且其中包含分页。然后放入你的高级逻辑,一旦证明了这一点,继续往下。我们曾经用铅笔和纸(通常在旧程序列表的背面)设计程序,我们使用铅笔,纸和大脑进行设计。然后将设计转移到&#34;骨架&#34;做我们想要的基础的程序。添加细节,从高到低。在每个阶段我们都会进行桌面检查&#34;这意味着你再次查看代码,铅笔,纸和大脑。
然后使用编译器发现拼写错误。修复那些。得到一个干净的编译,你已经做了很多东西来让你的程序工作。
这样做,你会错过那些老鼠!&#34;在您编写代码后发现需要进行重大更改的时刻。
凭借经验,您可以在脑海中完成所有这些过程。
这些天你坐在电脑前。我仍然推荐&#34;纸和铅笔&#34;路由,即使您使用您的PC实现它。
如果您只是坐下来编写COBOL程序,然后在测试失败时对其进行修补,结果对任何人都不会有好处。
我现在看到你最初发布了整个程序。
你在100-内完成100-。即使您逃避获得另一个BFL(取决于编译器),这也不好。
您正在从屏幕上获取数据,由人类输入。您必须验证。
使用自由格式布局并不排除您使用缩进来帮助自己和其他任何人。
测试时,你必须非常努力地打破程序。否则,您的用户将在第一时间将其中断。
答案 1 :(得分:0)
您没有显示调用300-REPORT的控制逻辑,但根据您的操作方式,您的迷路时间可能会导致一些意外行为。你可能想要解决这个问题:
WRITE OF-LINE FROM WS-HEADER-SEP.
不能保证它会引起问题,但它可以。通常,您只需要在标签之后的句点和Cobol-85 +代码中段落的最后一段。