Income Tax Logic Questions

家住魔仙堡 提交于 2020-01-25 20:32:28

问题


I'm having some trouble figuring out the logic behind this.

I need to display a report calculating balance, interest and principal per month until the balance is zero.

As an example, if input is months=12, balance=25000, rate=4.5%, output should look like this:

 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

I'm not sure what to write after DISPLAY col-hdr and before STOP RUN. Any ideas?

   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:


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

Firstly, get that sorted out.

 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

That looks much more professional, and easy to produce. I don't like the "months" heading, because it is not clear what it means. Some capitalisation would be good as well, but those are up to you. Actual spacing you can sort out as well. In my experience, Principal would always be before Interest, and a figure of the Payment before that. The user will want to see the Payment, not have to work it out, and want to confirm the split of the payment, and visually verify the interest amount.

Maybe it's regional, however.

As Brian noted in a comment, you've had you elbow on the 9 key whilst defining the month in the detail line. Make it PIC 99 or PIC Z9.

You are writing your program as a "fall through" structure. Perhaps that is what you are used to with other languages. Mainly COBOL programs that you would see would have a different structure.

Here is your code re-arranged, also with attention paid to indentation, which is important for the human reader. The spacing I find useful, but is not as mandatory as the indentation:

   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
       .

You have assignments. COBOL does not. COBOL has COMPUTE, so you'll need to use that, although MOVE, ADD, SUBTRACT, DIVIDE and MULTIPLY can clarify as well:

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

Note that GIVING. SUBTRACT A FROM B will change the value of B. If you put GIVING C on the end, B will no longer be changed, instead the result will be placed in C. ADD A TO B changes B. ADD A B GIVING C does not (note this time no need for TO, although syntactically it can be there). Ensure you understand what ADD, SUBTRACT, MULTIPLY and DIVIDE can do.

It is possible to only use COMPUTE. Unlike myth, there is no performance penalty in this, but extra human-reader information is lost.

With modern COBOL compilers it is not necessary to start a program with an arbitrary procedure name (either SECTION or paragraph). It has no meaning, at all. So ditch this (unless dictated by tutor/site-standards):

   000-MAIN SECTION.

You have things like this:

       IF 0 > LOANAMT

And:

       PERFORM UNTIL LOANAMT > 0

I understand the point made by cshneid made in a comment, but there is consistency, and there is the fact that COBOL has no assignment statement. An expression in a conditional construct can never cause a change to any field involved in the expression.

       IF LOANAMT > 0 

Or:

       IF LOANAMT GREATER THAN 0 

Can be read, by the mythical average COBOL programmer, without pause.

       IF 0 < LOANAMT

Is more of a discontinuity. The reader has to stop and think what that means. There is no benefit in doing it that way, and there are disbenefits.

DISPLAY and ACCEPT are the COBOL verbs which vary the most from the COBOL standard, from compiler to compiler. To the COBOL 85 Standard, ACCEPT and DISPLAY are very plain. You are using a compiler with "Extended" ACCEPT and DISPLAY. This may (probably does) allow the entry of negative amounts, and may prevent the entry of non-numeric data, but you need to check the documentation for your compiler. It will be important that the data entered is numeric. It is easier to get a character in the number than to enter a negative value by accident.

From your original code:

       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.

Here, since 100-init is not PERFORMed, the program control will drop through into 200-ADDMONTH. Labels (paragraphs or SECTIONs) are just labels. They can be the target of a PERFORM, a GO TO, or they can be "fallen through" or "dropped into". They are unlike "subroutine" or "function" definitions in other languages you probably know.

So, 100-init will PERFORM 200-ADDMONTH until it is finished with, then it will fall into 200-ADDMONTH again. Never code that deliberately. Each paragraph/SECTION should be self-contained and not rely on the physical location of its content.

If 100-init were PERFORMed, you'd be OK. Sort of. Because you have a STOP RUN in 200-ADDMONTH. When 200-ADDMONTH is executed the first time, the program will stop executing. Not what you want.

I've not considered the logic of your actual calculation, just the methods of it. You have duplicated code, so that could go in another PERFORMed paragraph/SECTION.

Be aware of the difference between a paragraph and a SECTION when they are PERFORMed. A SECTION can (these days does not have to) contain paragraphs. When a SECTION is PERFORMed, control returns to the completed PERFORM before the next SECTION. When a paragraph is PERFORMed, control returns before the next paragraph. Paragraphs cannot contain other paragraphs. To PERFORM a range of paragraphs, THRU will be required on the PERFORM. Unless dictated by tutor/site-standards, avoid coding that. Again, it relies on the physical location of code. Which is bad.

These days, there should be no intrinsic need for SECTIONs, and no need (except diktat) for PERFORM ... THRU ....



来源:https://stackoverflow.com/questions/28622490/income-tax-logic-questions

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!