所得税逻辑问题 [英] Income Tax Logic Questions

查看:85
本文介绍了所得税逻辑问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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



例如,如果输入为months = 12,余额= 25000,费率= 4.5%,则输出应如下所示:

 个月的余额利息本金
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 之前。有任何想法吗?

 标识部门。 
程序ID。实践。
数据分区。
工作存储部分。

01 LOANFMT PIC $$$$,$$$,$$$。$$。
01 LOANAMT PIC S9V9(2)值0。
01 INTRATE PIC S9V9(2)值0。
01 INTFMT PIC 9.999。
01 NUMPIC PIC S9(3)值0。
01 MONFMT PIC ZZ9。
01 MONCNT PIC S999值1.
01 PMT PIC S9(9)V9(2)值0.
01 PMTFMT PIC $$$$,$$$,$$$。$ 9 。
01 TOTPMT PIC S9(9)V9(2)VALUE0。
01 TOTFMT PIC $$$$,$$$,$$$。$ 9。

01 col-hdr。
05 pic x(15)值月。
05 pic x(15)值余额。
05 pic x(15)值兴趣。
05 pic x(15)值主体。

01明细行。
05 Pic X(2)值空间。
05 DL-MONTH Pic X(999)值1.
05 Pic X(5)值空间。
05 DL-BALANCE Pic $$$$,$$$,$$$。$ 9。
05 Pic X(4)值空间。
05 DL-INTEREST Pic $$$$,$$$,$$$。$ 9。
05 Pic X(4)值空间。
05 DL-PRINCIPAL Pic $$$$,$$$,$$$。$ 9。


程序部门。
000-主要部分。
显示输入贷款金额:,无需提前
接受贷款
如果0> LOANAMT
直到LOANAMT执行> 0
显示贷款金额必须为正
显示输入贷款金额:,无需提前
接受贷款
最终执行
END-IF


显示输入年利率:,无需提前支付
接受INT $
如果0>诠释
直到诠释> 0
显示年利率必须为正
显示输入年利率:
不推进
接受利率
结束
结束如果

显示,请输入月数:不提前
接受数字月
如果0> NUMMONTHS美元
,直到NUMMONTHS美元> 0
显示月份数必须为正
显示输入月份数:没有
前进
接受数字月份
结束演出
END-IF

显示空间

搬移LOANAMT到LOANFMT
搬移到INTFMT
将数月移到MONFMT
将PMT移到PMTFMT
将TOPTMT移至TOTFMT

显示col-hdr

100-init。
DL余额=贷款
DL利息=贷款*(整数/月数)
DL-PRINCIPAL =贷款-DL利息
显示详细信息行
进行直到月末200个月= DL个月

200个月。
向DL月
添加1 DL-BALANCE = DL-BALANCE-DL-PRINCIPAL
DL-兴趣=贷款*(INTRATE / NUMMONTHS)
DL-PRINCIPAL =贷款- DL兴趣
显示详细信息行。




停止运行。


解决方案

 月余额利息本金
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

首先,整理一下。

 月份余额利息本金
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 99 PIC Z9



您正在将程序编写为穿透结构。也许这就是您习惯使用其他语言的原因。主要是您会看到的COBOL程序具有不同的结构。



这里是重新排列您的代码,同时还要注意缩进,这对人类读者很重要。我发现间距很有用,但不像缩进那样强制:

 程序分区。 
执行获取并验证用户输入
执行过程用户输入
执行生产报告
返回

获取并验证用户输入。
执行获取并验证贷款AMT
执行获取并验证贷款
执行获取并验证月

GET-AND-VALIDATE-LOAN-AMT。
显示输入贷款金额:,无需提前
接受贷款
如果0> LOANAMT
直到LOANAMT执行> 0
显示贷款金额必须为正
显示输入贷款金额:
无需提前
接受贷款
结束执行
END-如果

GET-AND-VALIDATE-INT-RATE。
显示输入年利率:,而无需提前支付
接受利率:
如果0>诠释
直到诠释> 0
显示年利率必须为正
显示输入年利率:
不提前
接受利率
最终执行
END-IF

GET-AND-VALIDATE-MONTHS。
显示输入月数:,无需提前
接受月数
如果0> NUMMONTHS美元
,直到NUMMONTHS美元> 0
DISPLAY月份数必须为正
DISPLAY输入月份数:
没有推进
接受数字月
结束演出
END-IF

过程用户输入。
执行GET-VALIDATE-MONTHS

将LOANAMT移至LOANFMT
移至INTFMT
将数月移至MONFMT
将PMT移至PMTFMT
将TOTPMT移至TOTFMT

产品报告。
显示空间[不知道您想要什么]
DISPLAY col-hdr
执行格式初始行
执行输出详细信息
执行FORMAT-MONTHS-TO-END

FORMAT-INITIAL-LINE。
DL余额=贷款
DL利息=贷款
*(整数
/ NUMMONTHS)
DL-PRINCIPAL =贷款$
-DL-利息

输出详细信息行。
显示详细信息行

FORMAT-MONTHS-TO-END。
执行NUMMONTHS = DL-MONTH
将DL-MONTH
加1 DL-BALANCE = DL-BALANCE
-DL-PRINCIPAL
DL-INTEREST =贷款
*(整数
/ NUMMONTHS)
DL-PRINCIPAL = LOANAMT
-DL-兴趣
执行输出详细信息
最终执行

您有作业。 COBOL没有。 COBOL具有 COMPUTE ,因此您需要使用它,尽管 MOVE ADD 减法除法乘数也可以澄清:

 格式初始行。 
将贷款转移到DL余额
计算DL利息=贷款
*(整数
/ NUMMONTHS)
从Loanamt减去DL利息
提供DL -PRINCIPAL

请注意赠予。从B减去A将更改B的值。如果在最后放置GIVING C,将不再更改B,而是将结果放置在C中。将A添加到B将更改为B。添加AB GIVING C不会(请注意,这一次无需 TO ,尽管从句法上讲它可以在那里)。确保您了解加,减,乘和除功能。



仅使用COMPUTE是可能的。与神话不同的是,这样做不会降低性能,但是会丢失额外的人类阅读器信息。



使用现代的COBOL编译器,不必以任意的方式启动程序过程名称( SECTION 或段落)。毫无意义。因此,抛弃这个(除非由导师/现场标准决定):

  000-MAIN部分。 

您有这样的事情:

 如果0> LOANAMT 

并且:

 直到贷款完成> 0 

我理解cshneid在评论中的观点,但是有一致性,并且有COBOL没有赋值语句的事实。条件构造中的表达式永远不会导致表达式中涉及的任何字段发生变化。

 如果LOANAMT> 0 

或:

 如果LOANAMT大于0 

可由神话般的普通COBOL程序员阅读

 如果0 < LOANAMT 

更多是不连续的。读者必须停下来思考这意味着什么。这样做没有好处,而且有弊端。



DISPLAY ACCEPT 是不同的COBOL动词大部分来自COBOL标准,从编译器到编译器。对于COBOL 85标准,接受和显示非常简单。您正在使用带有扩展接受和显示的编译器。这可能(可能确实)允许输入负数,并且可能阻止输入非数字数据,但是您需要检查编译器的文档。输入的数据必须是数字,这一点很重要。在数字中获得一个字符比偶然输入一个负值要容易得多。



从原始代码开始:

  100-init。 
DL余额=贷款
DL利息=贷款*(整数/月数)
DL-PRINCIPAL =贷款-DL利息
显示详细信息行
进行直到月末200个月= DL个月

200个月。
向DL月
添加1 DL-BALANCE = DL-BALANCE-DL-PRINCIPAL
DL-兴趣=贷款*(INTRATE / NUMMONTHS)
DL-PRINCIPAL =贷款- DL兴趣
显示详细信息行。

停止运行。

在这里,因为100-init不是 PERFORM ed,程序控件将进入200-ADDMONTH。标签(段落或小节)仅仅是标签。它们可以成为PERFORM(执行),GO TO(转到)的目标,也可以掉进去或掉进去。它们与您可能知道的其他语言中的子例程或函数定义不同。



因此,100-init将执行200-ADDMONTH,直到完成为止,然后它将再次下降到200-ADDMONTH。 从不故意进行编码。每个段落/节都应该是独立的,不要依赖其内容的物理位置。



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



我没有考虑实际计算的逻辑,只是考虑了计算方法。您已经复制了代码,因此可以在另一个执行的段落 / SECTION中使用。



请注意,当执行时,段落和SECTION的区别。 SECTION可以(如今不必)包含段落。当执行了SECTION时,控制权将在下一个SECTION之前返回完成的PERFORM。当执行一个段落时,控件将在下一个段落之前返回。段落不能包含其他段落。要执行一系列段落,PERFORM上需要THRU。除非教师/现场标准规定,否则请避免对其进行编码。同样,它依赖于代码的物理位置。

这些天来,应该没有对SECTION的内在需求,也不需要(除了diktat之外)PERFORM ... THRU ....


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.

解决方案

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

这篇关于所得税逻辑问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆