所得税逻辑问题

Joh*_*ame 0 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
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)

Bil*_*ger 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
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 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
       .
Run Code Online (Sandbox Code Playgroud)

你有作业.COBOL没有.COBOL有COMPUTE,所以你需要使用的,虽然MOVE,ADD,SUBTRACT,DIVIDEMULTIPLY可以澄清,以及:

   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)

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

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