所得税逻辑问题

时间:2015-02-20 05:54:34

标签: cobol

我在弄清楚这背后的逻辑时遇到了一些麻烦。

我需要显示一份报告,计算每月的余额,利息和本金,直到余额为零。

例如,如果输入为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

我不确定在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.

1 个答案:

答案 0 :(得分:6)

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

首先,整理出来。

 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

看起来更专业,更容易制作。我不喜欢“月”标题,因为它不清楚它是什么意思。一些资本化也会很好,但这取决于你。您也可以整理实际间距。根据我的经验,校长将始终在利息之前,并且在此之前是付款的数字。用户将希望看到付款,而不是必须解决,并且想要确认付款的分割,并在视觉上验证利息金额。

然而,也许它是区域性的。

正如Brian在评论中指出的那样,你已经让你肘击9键,同时在细节线中定义月份。将其设为PIC 99PIC 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
       .

你有作业。 COBOL没有。 COBOL有COMPUTE,因此您需要使用它,尽管MOVEADDSUBTRACTDIVIDEMULTIPLY可以澄清为好:

   FORMAT-INITIAL-LINE.
       MOVE LOANAMT                TO DL-BALANCE                 
       COMPUTE DL-INTEREST         = LOAN 
                                   * ( INTRATE 
                                     / NUMMONTHS )
       SUBTRACT DL-INTEREST        FROM LOANAMT
         GIVING                    DL-PRINCIPAL
       .

请注意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.

你有这样的事情:

       IF 0 > LOANAMT

       PERFORM UNTIL LOANAMT > 0

我理解cshneid在评论中提出的观点,但是存在一致性,并且事实上COBOL没有赋值语句。条件构造中的表达式永远不会导致对表达式中涉及的任何字段进行更改。

       IF LOANAMT > 0 

或者:

       IF LOANAMT GREATER THAN 0 

神秘的普通COBOL程序员可以毫不停顿地阅读。

       IF 0 < LOANAMT

更多的是不连续性。读者必须停下来思考这意味着什么。这样做没有任何好处,并且有不利之处。

DISPLAYACCEPT是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.

这里,由于100-init不是PERFORM,程序控制将进入200-ADDMONTH。标签(段落或SECTION)只是标签。他们可以成为PERFORM,GO TO的目标,或者他们可以“堕落”或“落入”。它们与您可能知道的其他语言中的“子程序”或“函数”定义不同。

因此,100-init将执行200-ADDMONTH直到完成,然后它将再次落入200-ADDMONTH。 从不故意编码。每个段落/部分应该是独立的,而不是依赖于其内容的物理位置。

如果执行了100-init,你就可以了。有点。因为您在200-ADDMONTH中有STOP RUN。第一次执行200-ADDMONTH时,程序将停止执行。不是你想要的。

我没有考虑你实际计算的逻辑,只考虑它的方法。您有重复的代码,因此可以使用另一个PERFORMed段落/部分。

在执行时,请注意段落与SECTION之间的区别。 SECTION可以(这些天不必)包含段落。当执行SECTION时,控制将在下一个SECTION之前返回到完成的PERFORM。当一个段落被执行时,控制在下一个段落之前返回。段落不能包含其他段落。要执行一系列段落,PERFORM将需要THRU。除非由导师/网站标准规定,否则请避免编码。同样,它依赖于代码的物理位置。这很糟糕。

现在,对于SECTION而言,应该没有内在的需求,并且不需要(除了diktat)PERFORM ... THRU ....