No announcement yet.

?Rounding errors?

  • Filter
  • Time
  • Show
Clear All
new posts

    ?Rounding errors?

    Because of a recent post, I decided to dust off and polish up
    an old loan amortization program that I wrote some years ago.
    Now to the best of recollation, the old program, written in
    PB/DOS 2.1f was accurate down to the penny right up to the last
    month of the repayment period.

    With PB/DOS 3.5, under certain circumstances, an error occurs
    that I haven't been able to narrow down.

    For example, if I enter loan data for 30 years, (360 months),
    it sometimes over-runs to 361 months. Now I assume this is due
    to rounding errors but I haven't been able to "debug" this and
    it's driving me nuts. Can anyone give me some ideas without me
    posting the source code? TIA.

    BTW: I don't have 2.1f anymore. I lost it after I found out
    that windows, by default, doesn't backup .EXE files.

    There are no atheists in a fox hole or the morning of a math test.
    If my flag offends you, I'll help you pack.

    Check all loop counters (FOR...NEXT) and WHILE/DO..WHILE|UNTIL.

    Make sure all 'end of loop' conditions are integer; or, the 'done with the loop' comparison is made against a difference, like:
      DO UNTIL ABS(lastval# - thisval#) < .00001!
    .. or something like that.

    Hopefully, you have not written too much code using something like..
      IF Z# < | > |= X# THEN
         [b]EXIT FOR[/b]
    .. because then you'll have to go through your code line-by-line looking for any statement in which you do a numeric comparison of non-integers.

    Michael Mattias
    Tal Systems (retired)
    Port Washington WI USA
    [email protected]


      You might also consider changing to the FIX datatype with FIXDIGITS=4, which gives you the equivalent of a CURRENCY datatype... which of course is perfect for money calculations.

      Michael Mattias
      Tal Systems (retired)
      Port Washington WI USA
      [email protected]


        Thanks for the tips MM but no go. There's nothing wrong with
        the loop counters. They work as advertised. It seems to be
        with the ?rounding errors? in the calcuations.

        If anyone has a commercial loan program, could you please enter
        the following values and see if it bleeds over to 361 months on
        your program.

        Loan amount: $80,000
        Term: 30 years (360 months)
        Interest: 5.5 percent APR

        This bleed over doesn't happen all the time. Just occasionally.

        There are no atheists in a fox hole or the morning of a math test.
        If my flag offends you, I'll help you pack.


          > it seems to be with the ?rounding errors? in the calcuations

          since you refuse to post even a piece of code (fwiw, amortization is hardly a trade secret), just check your data types.

          if float? you have rounding problems, and you must handle them.

          you have it easy, because you know about the need to round your floats.

          i had it a little tougher because i had to find a little problem in the compiler first:

          (fwiw, there's some rounding code in there you can probably use).

          Michael Mattias
          Tal Systems (retired)
          Port Washington WI USA
          [email protected]


            I'm not refusing to post my code. I simply would prefer not to
            if I don't have to. Here is what I have so far. The program
            isn't finished. I would like to find out where the rounding
            errors are before I go on to future things.
            	$lib all off
            	color 14,1
                    f$ = "$###,###.##"
                    locate  5,29 : Print;"Regular payment on a loan"
            	locate  7,25 : Input;"Term in years: ",years
                    if years = 0 then exit loop
                    locate  9,25 : Input;"    Principal: ",principal
                    if principal = 0 then exit loop
                    save = principal
                    locate 11,25 : Input;"Interest rate: ",interest
                    if interest = 0 then exit loop
                    monthly = 12				'Monthly payments
            REM	Computer monthly payments
                    te = ((interest / 100) * principal / monthly) / _
                         (1-1 / ((interest / 100) / monthly + 1) ^ (monthly * years))
                    payment = int(te * 100 + .5) / 100
            REM     This is the mod that I came up with in response to Pauls
            REM     response. It seems to work in as far as making the 
            REM     months come out exact.
                    te$ = str$(te)
                    p = instr(te$,".")
                    if p = 0 then te$ = te$ + ".000"
                    te = val(mid$(te$,p+3,1))
                    if te < 5 then payment = payment + .01
                    t$ = using$(f$,payment)
                    t$ = remove$(t$," ")
                    locate 15,22 : print;"Regular payments: ";t$
                    locate 17,10
                    print;"Press ESCape to end the program or any other key to"
                    locate 18,10
                    print;"write the data to a disk file."
                    if abort = 0 then
                    fi$ = "amort.txt"
                    te$ = dir$(fi$)
                    if te$ <> "" then kill fi$
                    open fi$ for binary as #1
                    crlf$ = chr$(13) + chr$(10)
                    separator$ = string$(75,"-") + crlf$
                    m$ = "Original loan amount: " + using$(f$,principal) + crlf$
               m$ = m$ + "      Length of loan: " + Str$(years) + " Years" + crlf$
               m$ = m$ + "       Interest Rate: " + str$(interest) + " Percent" + crlf$
               m$ = m$ + crlf$
               m$ = m$ + "     Monthly Payment: " + using$(f$,payment)
               m$ = m$ + crlf$ + crlf$
            	put$ #1,m$
            	put$ #1,separator$
            	put$ #1,"Month"      + space$(5)
            	put$ #1,"Interest"   + space$(5)
            	put$ #1,"Principal"  + space$(8)
            	put$ #1,"Balance"    + space$(7)
            	put$ #1,"Equity"     + space$(5)
                    put$ #1,"Accr Inter" + crlf$
            	put$ #1,separator$
                    for month = 1 to monthly * years + 5
            REM	Calculate interest paid with each payment
            	tointerest = int((principal * (interest / 100) / monthly) * 100 + .5) / 100
            REM	Add up the accumulated interest
            	accum = accum + tointerest
            REM     How much of the payment goes to principal
                    toprincipl = payment - tointerest
            REM     How much equity is built up
            	equity = equity + toprincipl
                    if equity > save then equity = save
            REM     How much of the principal is left
                    principal  = principal - toprincipl
            REM	Zero out a negative number
                    if principal < 0 then principal = 0
                    t1$ = using$(f$,tointerest) : t1$ = remove$(t1$," ")
                    t2$ = using$(f$,toprincipl) : t2$ = remove$(t2$," ")
                    t3$ = using$(f$,principal)  : t3$ = remove$(t3$," ")
                    t4$ = using$(f$,equity)     : t4$ = remove$(t4$," ")
                    t5$ = using$(f$,accum)      : t5$ = remove$(t5$," ")
                    te$ = space$(2) + using$("###",month)
                    te$ = te$ + space$(13 - len(t1$)) + t1$
                    for x = len(te$) to 31 - len(t2$)
                    te$ = te$ + " "
                    next x
            	te$ = te$ + t2$
                    for x = len(te$) to 46 - len(t3$)
                    te$ = te$ + " "
                    next x
            	te$ = te$ + t3$
                    for x = len(te$) to 59 - len(t4$)
                    te$ = te$ + " "
                    next x
                    te$ = te$ + t4$
                    for x = len(te$) to 74 - len(t5$)
                    te$ = te$ + " "
                    next x
                    te$ = te$ + t5$
            	put$ #1,te$ + crlf$
            rem	print;te$
                    if principal <= 0 then exit for
                    if month / 12 = int(month / 12) then
                    put$ #1,string$(75,"-") + crlf$
                    end if
                    next month
                    close #1
            	m$ = "Finished writing to " + chr$(34) + "AMORT.TXT" + chr$(34)
                    m$ = m$ + " file."
                    col = 40 - int(len(m$) / 2)
                    locate 20,col : print;m$;
            REM     I didn't include an LPRINT routine since a lot of printers
            REM     are of the USB variety. Can't get there from here.
                    m$ = "Bring up your favorite ASCII word processor to print it out."
                    col = 40 - int(len(m$) / 2)
                    locate 21,col
                    end if
                    m$ = "Tap ESCape to end or any other key to compute another"
                    col = 40 - int(len(m$) / 2)
                    locate 22,col
                    t = abort
                    if t = 1 then exit loop
            function abort
            	while instat=0:wend
                    an$ = inkey$
                    if an$ = chr$(27) then
                    function = 1
                    function = 0
                    end if
                    end function


            [This message has been edited by Mel Bishop (edited August 03, 2004).]
            There are no atheists in a fox hole or the morning of a math test.
            If my flag offends you, I'll help you pack.


              the problem is the line :

              payment = int(te * 100 + .5) / 100

              te is calculated as $454.2312

              The above line makes this int(45423.62)/100 = $454.23

              This is less than the 454.2312 needed to repay the loan on time so there is a shortfall of $0.0012 per month. This accumulates to give the 361st payment.

              You need to change the above line so that the repayment is ALWAYS higher (rounded up to the nearest cent) than the exact figure required to pay off the loan on time.
              What you're doing is rounding to the nearest cent even if that means rounding down.. which will then leave a shortfall.




                Originally posted by Paul Dixon:
                the problem is the line...
                Okay, let me do some razzle-dazzle and see what I come up with.
                I'll let you know. Thanks.

                There are no atheists in a fox hole or the morning of a math test.
                If my flag offends you, I'll help you pack.