我在弄清楚这背后的逻辑时遇到了一些麻烦.
我需要显示一份报告,计算每月的余额,利息和本金,直到余额为零.
例如,如果输入为months = 12,balance = 25000,rate = 4.5%,则输出应如下所示:
months balance interest principal
1 $25000.00 $93.75 $2,040.71
2 $22,959.29 $86.10 $2,048.36
.......
12 $2,126.53 $7.97 $2,126.49
Run Code Online (Sandbox Code Playgroud)
我不知道DISPLAY col-hdr之前和之后要写什么STOP RUN.有任何想法吗?
IDENTIFICATION DIVISION.
PROGRAM-ID. practice.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 LOANFMT PIC $$$$,$$$,$$$.$$.
01 LOANAMT PIC S9(9)V9(2) VALUE 0.
01 INTRATE PIC S9V9(2) VALUE 0.
01 INTFMT PIC 9.999.
01 NUMMONTHS PIC S9(3) VALUE 0.
01 MONFMT PIC ZZ9.
01 MONCNT PIC S999 VALUE 1.
01 PMT PIC S9(9)V9(2) VALUE 0.
01 PMTFMT PIC $$$$,$$$,$$$.$9.
01 TOTPMT PIC S9(9)V9(2) VALUE 0.
01 TOTFMT PIC $$$$,$$$,$$$.$9.
01 col-hdr.
05 pic x(15) value "Month".
05 pic x(15) value "Balance".
05 pic x(15) value "Interest".
05 pic x(15) value "Principal".
01 Detail-Line.
05 Pic X(2) Value Spaces.
05 DL-MONTH Pic X(999) VALUE 1.
05 Pic X(5) Value Spaces.
05 DL-BALANCE Pic $$$$,$$$,$$$.$9.
05 Pic X(4) Value Spaces.
05 DL-INTEREST Pic $$$$,$$$,$$$.$9.
05 Pic X(4) Value Spaces.
05 DL-PRINCIPAL Pic $$$$,$$$,$$$.$9.
PROCEDURE DIVISION.
000-MAIN SECTION.
DISPLAY "Enter Loan Amount: " WITH NO ADVANCING
ACCEPT LOANAMT
IF 0 > LOANAMT
PERFORM UNTIL LOANAMT > 0
DISPLAY "Loan Amount must be positive"
DISPLAY "Enter Loan Amount: " WITH NO ADVANCING
ACCEPT LOANAMT
end-PERFORM
END-IF
DISPLAY "Enter Annual Interest Rate: " WITH NO ADVANCING
ACCEPT INTRATE
IF 0 > INTRATE
PERFORM UNTIL INTRATE > 0
DISPLAY "Annual Interest Rate must be positive"
DISPLAY "Enter Annual Interest Rate: " WITH
NO ADVANCING
ACCEPT INTRATE
end-PERFORM
END-IF
DISPLAY "Enter Number of Months: " WITH NO ADVANCING
ACCEPT NUMMONTHS
IF 0 > NUMMONTHS
PERFORM UNTIL NUMMONTHS > 0
DISPLAY "Number of Months must be positive"
DISPLAY "Enter Number of Months: " WITH NO
ADVANCING
ACCEPT NUMMONTHS
end-PERFORM
END-IF
DISPLAY SPACE
move LOANAMT TO LOANFMT
move INTRATE TO INTFMT
MOVE NUMMONTHS TO MONFMT
MOVE PMT TO PMTFMT
MOVE TOTPMT TO TOTFMT
DISPLAY col-hdr
100-init.
DL-BALANCE = LOANAMT
DL-INTEREST = LOAN * (INTRATE/NUMMONTHS)
DL-PRINCIPAL = LOANAMT - DL-INTEREST
DISPLAY DETAIL-LINE
PERFORM 200-ADDMONTH UNTIL NUMMONTHS = DL-MONTH
200-ADDMONTH.
ADD 1 TO DL-MONTH
DL-BALANCE = DL-BALANCE - DL-PRINCIPAL
DL-INTEREST = LOAN * (INTRATE/NUMMONTHS)
DL-PRINCIPAL = LOANAMT - DL-INTEREST
DISPLAY DETAIL-LINE.
STOP RUN.
Run Code Online (Sandbox Code Playgroud)
months balance interest principal
1 $25000.00 $93.75 $2,040.71
2 $22,959.29 $86.10 $2,048.36
.......
12 $2,126.53 $7.97 $2,126.49
Run Code Online (Sandbox Code Playgroud)
首先,整理出来.
months balance interest principal
01 $25,000.00 $93.75 $2,040.71
02 $22,959.29 $86.10 $2,048.36
.......
12 $2,126.53 $7.97 $2,126.49
Run Code Online (Sandbox Code Playgroud)
这看起来更专业,更容易生产.我不喜欢"月"标题,因为它不清楚它是什么意思.一些资本化也会很好,但这取决于你.您也可以整理实际间距.根据我的经验,校长将始终在利息之前,并且在此之前是付款的数字.用户将希望看到付款,而不是必须解决,并且想要确认付款的分割,并在视觉上验证利息金额.
然而,也许这是区域性的.
正如布莱恩在评论中指出的那样,9在细节线中定义月份的同时,你已经肘击了钥匙.使它成为PIC 99或PIC Z9.
您正在将程序编写为"直通"结构.也许这就是你习惯使用其他语言的东西.您将看到的主要是COBOL程序将具有不同的结构.
这是你的代码重新安排,也注意缩进,这对人类读者很重要.我发现有用的间距,但不像缩进那样强制:
PROCEDURE DIVISION.
PERFORM GET-AND-VALIDATE-USER-INPUT
PERFORM PROCESS-USER-INPUT
PERFORM PRODUCE-REPORT
GOBACK
.
GET-AND-VALIDATE-USER-INPUT.
PERFORM GET-AND-VALIDATE-LOAN-AMT
PERFORM GET-AND-VALIDATE-INT-RATE
PERFORM GET-AND-VALIDATE-MONTHS
.
GET-AND-VALIDATE-LOAN-AMT.
DISPLAY "Enter Loan Amount: " WITH NO ADVANCING
ACCEPT LOANAMT
IF 0 > LOANAMT
PERFORM UNTIL LOANAMT > 0
DISPLAY "Loan Amount must be positive"
DISPLAY "Enter Loan Amount: "
WITH NO ADVANCING
ACCEPT LOANAMT
end-PERFORM
END-IF
.
GET-AND-VALIDATE-INT-RATE.
DISPLAY "Enter Annual Interest Rate: " WITH NO ADVANCING
ACCEPT INTRATE
IF 0 > INTRATE
PERFORM UNTIL INTRATE > 0
DISPLAY "Annual Interest Rate must be positive"
DISPLAY "Enter Annual Interest Rate: "
WITH NO ADVANCING
ACCEPT INTRATE
end-PERFORM
END-IF
.
GET-AND-VALIDATE-MONTHS.
DISPLAY "Enter Number of Months: " WITH NO ADVANCING
ACCEPT NUMMONTHS
IF 0 > NUMMONTHS
PERFORM UNTIL NUMMONTHS > 0
DISPLAY "Number of Months must be positive"
DISPLAY "Enter Number of Months: "
WITH NO ADVANCING
ACCEPT NUMMONTHS
end-PERFORM
END-IF
.
PROCESS-USER-INPUT.
PERFORM GET-AND-VALIDATE-MONTHS
move LOANAMT TO LOANFMT
move INTRATE TO INTFMT
MOVE NUMMONTHS TO MONFMT
MOVE PMT TO PMTFMT
MOVE TOTPMT TO TOTFMT
.
PRODUCE-REPORT.
DISPLAY SPACE [don't know what you want that for]
DISPLAY col-hdr
PERFORM FORMAT-INITIAL-LINE
PERFORM OUTPUT-DETAIL-LINE
PERFORM FORMAT-MONTHS-TO-END
.
FORMAT-INITIAL-LINE.
DL-BALANCE = LOANAMT
DL-INTEREST = LOAN
* ( INTRATE
/ NUMMONTHS )
DL-PRINCIPAL = LOANAMT
- DL-INTEREST
.
OUTPUT-DETAIL-LINE.
DISPLAY DETAIL-LINE
.
FORMAT-MONTHS-TO-END.
PERFORM NUMMONTHS = DL-MONTH
ADD 1 TO DL-MONTH
DL-BALANCE = DL-BALANCE
- DL-PRINCIPAL
DL-INTEREST = LOAN
* ( INTRATE
/ NUMMONTHS )
DL-PRINCIPAL = LOANAMT
- DL-INTEREST
PERFORM OUTPUT-DETAIL-LINE
END-PERFORM
.
Run Code Online (Sandbox Code Playgroud)
你有作业.COBOL没有.COBOL有COMPUTE,所以你需要使用的,虽然MOVE,ADD,SUBTRACT,DIVIDE和MULTIPLY可以澄清,以及:
FORMAT-INITIAL-LINE.
MOVE LOANAMT TO DL-BALANCE
COMPUTE DL-INTEREST = LOAN
* ( INTRATE
/ NUMMONTHS )
SUBTRACT DL-INTEREST FROM LOANAMT
GIVING DL-PRINCIPAL
.
Run Code Online (Sandbox Code Playgroud)
请注意GIVING.从B中减去B将改变B的值.如果你把GIVING C放在最后,B将不再被改变,而是将结果放在C. ADD A TO B改变B. ADD AB GIVING C没有(注意这次不需要TO,虽然从语法上来说它可以在那里).确保您了解ADD,SUBTRACT,MULTIPLY和DIVIDE可以做什么.
它可能只使用COMPUTE.与神话不同,这并没有性能损失,但会丢失额外的人类读者信息.
使用现代COBOL编译器,没有必要启动具有任意过程名称(SECTION或者段落)的程序.根本没有任何意义.所以放弃这个(除非由导师/网站标准决定):
000-MAIN SECTION.
Run Code Online (Sandbox Code Playgroud)
你有这样的事情:
IF 0 > LOANAMT
Run Code Online (Sandbox Code Playgroud)
和:
PERFORM UNTIL LOANAMT > 0
Run Code Online (Sandbox Code Playgroud)
我理解cshneid在评论中提出的观点,但是存在一致性,并且事实上COBOL没有赋值语句.条件构造中的表达式永远不会导致对表达式中涉及的任何字段的更改.
IF LOANAMT > 0
Run Code Online (Sandbox Code Playgroud)
要么:
IF LOANAMT GREATER THAN 0
Run Code Online (Sandbox Code Playgroud)
可以通过神话般的平均COBOL程序员阅读,不会停顿.
IF 0 < LOANAMT
Run Code Online (Sandbox Code Playgroud)
更多的是不连续性.读者必须停下来思考这意味着什么.这样做没有任何好处,并且有不利之处.
DISPLAY和ACCEPT是COBOL动词,其改变从COBOL标准最大,从编译器编译器.对于COBOL 85标准,ACCEPT和DISPLAY非常简单.您正在使用带有"Extended"ACCEPT和DISPLAY的编译器.这可能(可能确实)允许输入负数,并可能阻止输入非数字数据,但您需要检查编译器的文档.输入的数据必须是数字.在数字中获取字符比在意外输入负值更容易.
从您的原始代码:
100-init.
DL-BALANCE = LOANAMT
DL-INTEREST = LOAN * (INTRATE/NUMMONTHS)
DL-PRINCIPAL = LOANAMT - DL-INTEREST
DISPLAY DETAIL-LINE
PERFORM 200-ADDMONTH UNTIL NUMMONTHS = DL-MONTH
200-ADDMONTH.
ADD 1 TO DL-MONTH
DL-BALANCE = DL-BALANCE - DL-PRINCIPAL
DL-INTEREST = LOAN * (INTRATE/NUMMONTHS)
DL-PRINCIPAL = LOANAMT - DL-INTEREST
DISPLAY DETAIL-LINE.
STOP RUN.
Run Code Online (Sandbox Code Playgroud)
这里,由于没有PERFORM编辑100-init ,程序控制将进入200-ADDMONTH.标签(段落或SECTION)只是标签.他们可以成为PERFORM,GO TO的目标,或者他们可以"堕落"或"落入".它们与您可能知道的其他语言中的"子程序"或"函数"定义不同.
因此,100-init将执行200-ADDMONTH直到完成,然后它将再次落入200-ADDMONTH.永远不要故意编码.每个段落/ SECTION应该是独立的,而不是依赖于其内容的物理位置.
如果执行100-init,你就可以了.有点.因为你有STOP RUN200-ADDMONTH.第一次执行200-ADDMONTH时,程序将停止执行.不是你想要的.
我没有考虑你实际计算的逻辑,只考虑它的方法.您有重复的代码,因此可以进入另一个PERFORMed段落/部分.
在执行时,请注意段落与SECTION之间的区别.SECTION可以(这些天不必)包含段落.当执行SECTION时,控制将在下一个SECTION之前返回到完成的PERFORM.当一个段落被执行时,控制在下一个段落之前返回.段落不能包含其他段落.要执行一系列段落,PERFORM将需要THRU.除非由导师/网站标准规定,否则请避免编码.同样,它依赖于代码的物理位置.这很糟糕.
这些天,SECTION不应该有内在的需要,并且不需要(除了diktat)PERFORM ... THRU ....