gnucash/libgnucash/app-utils/calculation/fin.c
John Ralls bf55c30aeb Fix most of the unused assignment errors from static analysis.
There are a very few left that need deeper study, but this gets
rid of most of the noise. For the most part it's just getting rid of
extra variables or removing an assignment that is always
replaced later but before any reads of the variable. A few are
discarded result variables.
2018-11-30 15:08:41 +09:00

2475 lines
83 KiB
C
Raw Blame History

/***************************************************************************
fin.c - description
-------------------
begin : Thursday June 15 2000
email : tboldt@attglobal.net
Author : Terry D. Boldt
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
/*
* Functions to compute financial equations and amortization schedules
* 6-15-2000
*
*/
/*
* Financial Calculator
*
* This version for use WITH ANSI.SYS display driver
*
* This is a complete financial computation utility to solve for the
* five * standard financial values: n, %i, PV, PMT and FV
*
* n == number of payment periods
* %i == nominal interest rate, NAR, charged
* PV == Present Value
* PMT == Periodic Payment
* FV == Future Value
*
* In addition, two additional parameters may be specified:
*
* 1) Compounding Frequency per year, CF. The compounding frequency
* per year may be discrete or continuous and may be different from
* the Payment Frequency per year
*
* 2) Payment Frequency per year, PF. Payments may be made at the
* beginning or the end of the payment period.
*
* When an amortization schedule is desired, the financial
* transaction Effective Date, ED, and Initial Payment Date, IP, must
* also be entered.
*
* Canadian and European style mortgages can be handled in a simple,
* straight-forward manner. Standard financial sign conventions are
* used:
*
* "Money paid out is Negative, Money received is Positive"
*
* Time value of money:
*
* If you borrow money, you can expect to pay rent or interest for its use;
* conversely you expect to receive rent interest on money you loan or invest.
* When you rent property, equipment, etc., rental payments are normal; this
* is also true when renting or borrowing money. Therefore, money is
* considered to have a "time value". Money available now, has a greater value
* than money available at some future date because of its rental value or the
* interest that it can produce during the intervening period.
*
* Simple Interest:
*
* If you loaned $800 to a friend with an agreement that at the end of one
* year he would would repay you $896, the "time value" you placed on your
* $800 (principal) was $96 (interest) for the one year period (term) of the
* loan. This relationship of principal, interest, and time (term) is most
* frequently expressed as an Annual Percentage Rate (APR). In this case the
* APR was 12.0% [(96/800)*100]. This example illustrates the four basic
* factors involved in a simple interest case. The time period (one year),
* rate (12.0% APR), present value of the principal ($800) and the future
* value of the principal including interest ($896).
*
* Compound Interest:
*
* In many cases the interest charge is computed periodically during the term
* of the agreement. For example, money left in a savings account earns
* interest that is periodically added to the principal and in turn earns
* additional interest during succeeding periods. The accumulation of interest
* during the investment period represents compound interest. If the loan
* agreement you made with your friend had specified a "compound interest
* rate" of 12% (compounded monthly) the $800 principal would have earned
* $101.46 interest for the one year period. The value of the original $800
* would be increased by 1% the first month to $808 which in turn would be
* increased by 1% to 816.08 the second month, reaching a future value of
* $901.46 after the twelfth iteration. The monthly compounding of the nominal
* annual rate (NAR) of 12% produces an effective Annual Percentage Rate (APR)
* of 12.683% [(101.46/800)*100]. Interest may be compounded at any regular
* interval; annually, semiannually, monthly, weekly, daily, even continuously
* (a specification in some financial models).
*
* Periodic Payments:
*
* When money is loaned for longer periods of time, it is customary for the
* agreement to require the borrower to make periodic payments to the lender
* during the term of the loan. The payments may be only large enough to repay
* the interest, with the principal due at the end of the loan period (an
* interest only loan), or large enough to fully repay both the interest and
* principal during the term of the loan (a fully amoritized loan). Many loans
* fall somewhere between, with payments that do not fully cover repayment of
* both the principal and interst. These loans require a larger final payment
* (balloon) to complete their amortization. Payments may occur at the
* beginning or end of a payment period. If you and your friend had agreed on
* monthly repayment of the $800 loan at 12% NAR compounded monthly, twelve
* payments of $71.08 for a total of $852.96 would be required to amortize the
* loan. The $101.46 interest from the annual plan is more than the $52.96
* under the monthly plan because under the monthly plan your friend would not
* have had the use of $800 for a full year.
*
* Financial Transactions:
*
* The above paragraphs introduce the basic factors that govern most
* financial transactions; the time period, interest rate, present value,
* payments and the future value. In addition, certain conventions must be
* adhered to: the interest rate must be relative to the compounding frequency
* and payment periods, and the term must be expressed as the total number of
* payments (or compounding periods if there are no payments). Loans, leases,
* mortgages, annuities, savings plans, appreciation, and compound growth are
* among the many financial problems that can be defined in these terms. Some
* transactions do not involve payments, but all of the other factors play a
* part in "time value of money" transactions. When any one of the five (four
* - if no payments are involved) factors is unknown, it can be derived from
* formulas using the known factors.
*
* Standard Financial Conventions Are:
*
* Money RECEIVED is a POSITIVE value and is represented by an arrow
* above * the line
*
* Money PAID OUT is a NEGATIVE value and is represented by an arrow
* below * the line.
*
* If payments are a part of the transaction, the number of payments
* must * equal the number of periods (n).
*
* Payments may be represented as occurring at the end or beginning of
* the * periods.
*
* Diagram to visualize the positive and negative cash flows (cash
* flow * diagrams):
*
* Amounts shown above the line are positive, received, and amounts
* shown below the line are negative, paid out.
*
* 1)
* FV*
* 1 2 3 4 . . . . . . . . . n <20>
* Period <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* <20>
*
* PV
*
* Appreciation
* Depreciation
* Compound Growth
* Savings Account
*
* ****************************************************************************
*
* 2) FV
* PV = 0
* <20>
* Period <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* <20> 1 <20> 2 <20> 3 <20> 4 <20> . <20> . <20> . <20> . <20> . <20> . <20> . <20> . <20> . <20> n
*
* PMT PMT PMT PMT PMT PMT PMT PMT PMT PMT PMT PMT PMT PMT
*
* Annuity (series of payments)
* Pension Fund
* Savings Plan
* Sinking Fund
*
* ****************************************************************************
*
* 3)
* PV
* <20> FV=0
* Period <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ŀ
* 1 <20> 2 <20> 3 <20> 4 <20> . <20> . <20> . <20> . <20> . <20> . <20> . <20> . <20> . <20> n <20>
*
* PMT PMT PMT PMT PMT PMT PMT PMT PMT PMT PMT PMT PMT PMT
*
* Amortization
* Direct Reduction Loan
* Mortgage (fully amortized)
*
* ****************************************************************************
*
* 4)
* FV*
* PMT PMT PMT PMT PMT PMT PMT PMT PMT PMT PMT PMT PMT <20> +
* PMT
* 1 <20> 2 <20> 3 <20> 4 <20> . <20> . <20> . <20> . <20> . <20> . <20> . <20> . <20> . <20> n <20>
* Period <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* <20>
*
* PV
*
* Annuity
* Lease (with buy back or residual)*
* Loan or Mortgage (with balloon)*
*
* ****************************************************************************
*
* First lets discuss interest before discussing the financial
* equation. Most financial transactions utilize a nominal interest
* rate, NAR, i.e., the interest rate per year. The NAR must be
* converted to the interest rate per payment interval and the
* compounding accounted for before it can be used in computing an
* interest payment. After this conversion process, the interest
* used is the effective interest rate, EIR. In converting NAR to
* EIR, there are two concepts to discuss first, the Compounding
* Frequency and the Payment Frequency and * whether the interest is
* coumpounded in discrete intervals or continuously. The
* compounding Frequency, CF, is simply the number of times per
* year, the monies in the financial transaction are compounded. In
* the U.S., monies are usually compounded daily on bank deposits,
* and monthly on loans. Somtimes Long term deposits are compounded
* quarterly or weekly.
*
* The Payment Frequency, PF, is simply how often during a year
* payments are made in the transaction. Payments are usually
* scheduled on a regular basis and can be made at the beginning or
* end of the payment period. If made at the beginning of the
* payment period, interest must be applied to the payment as well
* as any previous money paid or money still owed.
*
* Normal values for CF and PF are:
* 1 == annual
* 2 == semi-annual
* 3 == tri-annual
* 4 == quaterly
* 6 == bi-monthly
* 12 == monthly
* 24 == semi-monthly
* 26 == bi-weekly
* 52 == weekly
* 360 == daily
* 365 == daily
*
* a) the Compounding Frequency per year, CF, need not be identical
* to the Payment Frequency per year, PF, and/or,
*
* b) Interest may be compounded in either discrete intervals or continuously
* compounded.
*
* c) Also, payments may be made at the beginning of the payment
* period or at the end of the payment period.
*
* CF and PF are defaulted to 1. The default is for discrete interest
* intervals and payments are defaulted to the end of the payment
* period.
*
* When a solution for n, PV, PMT or FV is required, the nominal interest
* rate, i, must first be converted to the effective interest rate per payment
* period. This rate, ieff, is then used to compute the selected variable. To
* convert i to ieff, the following expressions are used:
*
* Discrete interest periods:
*
* 19) ieff = (1 + i/CF)^(CF/PF) - 1
*
* Continuous Interest
*
* 20) ieff = e^(i/PF) - 1 = exp(i/PF) - 1
*
* When interest is computed, the computation produces the effective interest
* rate, ieff. This value must then be converted to the nominal interest rate.
* Function _I below returns the nominal interest rate NOT the effective
* interest rate. ieff is converted to i using the following expressions:
*
* Discrete Case:
*
* i = CF*[(1+ieff)^(PF/CF) - 1]
*
* Continuous Case:
*
* i = ln[(1+ieff)^PF]
*
* ****************************************************************************
*
* NOTE: in the equations below for the financial transaction, all
* interest rates are the effective interest rate, ieff. The symbol
* will be shortned to just 'i'.
*
* ****************************************************************************
*
* The basic financial equation used is:
*
* 1) PV*(1 + i)^n + PMT*(1 + iX)*[(1+i)^n - 1]/i + FV = 0
* Where: X = 0 for end of period payments, and
* X = 1 for beginning of period payments
*
* ****************************************************************************
*
* NOTE: this equation is derived in the following manner:
*
* Start with the basic equation to find the balance or Present
* Value, PV[1], after one payment period. Note PV[1] is the Present
* value after on payment and PV[0] is the initial Present
* Value. PV[0] will be shortened to just PV.
*
* The interest due at the end of the first payment period is:
*
* ID[1] = (PV + X * PMT) * i
* where: X = 0 for end of period payments, and
* X = 1 for beginning of period payments.
*
* Thus:
* PV[1] = PV + (PMT + ID[1])
* = PV + (PMT + (PV + X * PMT) * i)
* = PV * (1 + i) + PMT * (1 + Xi)
*
* This equation works for all of the money diagrams shown
* above. The Present Value, money received or paid, is modified by
* a payment made at the beginning of a payment period and
* multiplied by the effective interest rate to compute the interest
* due during the payment period. The interest due is then added to
* the payment to obtain the amount to be added to the Present Value
* to compute the new Present Value.
*
* For diagram 1): PV < 0, PMT == 0, PV[1] < 0
* For diagram 2): PV == 0, PMT < 0, PV[1] < 0
* For Diagram 3): PV > 0, PMT < 0, PV[1] >= 0 or PV[1] <= 0
* For Diagram 4): PV < 0, PMT > 0, PV[1] <= 0 or PV[1] >= 0
*
* X may be 0 or 1 for any diagram.
*
* For the standard loan, PV is the money borrowed, PMT is the
* periodic payment to repay the loan and i is the effective
* interest rate agreed upon.
*
* To calculate the Present Value after the second payment period,
* the above calculation is applied iteratively to PV_1:
*
* PV[2] = PV[1] + (PMT + (PV[1] + X * PMT) * i)
* = PV[1] * (1 + i) + PMT * (1 + iX)
* = (PV * (1 + i) + PMT * (1 + iX)) * (1 + i) + PMT * (1 + iX)
* = PV * (1 + i)^2 + PMT * (1 + iX) * (1 + i)
* + PMT * (1 + iX)
*
* Similarly:
*
* PV[3] = PV[2] + (PMT + (PV[2] + X * PMT) * i)
* = PV[2] * (1 + i) + PMT * (1 + iX)
* = PV * (1 + i)^2 + PMT * (1 + iX) * (1 + i)
* + PMT * (1+ iX)) * ( 1 + i)
* + PMT * (1+ iX)
* = PV * (1 + i)^3 + PMT * (1 + iX) * (1 + i)^2
* + PMT * (1 + iX) * (1 + i)^2
* + PMT * (1 + iX) * (1 + i)
* + PMT * (1 + iX)
*
* And for the n'th payment:
*
* PV[n] = PV[n-1] + (PMT + (PV[n-1] + X * PMT) * i)
* PV[n] = PV * (1 + i)^n + PMT * (1 + iX) * (1 + i)^(n-1)
* + PMT * (1 + iX) * (1 + i)^(n-2) +
* .
* .
* .
* + PMT * (1 + iX) * (1 + i)
* + PMT * (1 + iX)
* PV[n] = PV * (1 + i)^n + PMT * (1 + iX) * [(1 + i)^(n-1) + ...
* + (1 + i) + 1]
*
* ****************************************************************************
*
* The sum of the finite series:
*
* 1 + k + (k^2) + (k^3) + ... + (k^n) = (1-k^(n+1))/(1-k)
*
* as can be seen by the following. Let S(n) be the series sum. Then
*
* S(n) - k * S(n) = 1 - k^(n+1)
*
* and solving for S(n):
*
* S(n) = [1-k^(n+1)]/[1-k] = 1 + k + (k^2) + (k^3) + ... + (k^n)
*
* ****************************************************************************
*
* PV[n] = PV * (1 + i)^n + PMT * (1 + iX) * [(1 + i)^(n-1) + ...
* + (1 + i) + 1]
* = PV * (1 + i)^n + PMT * (1 + iX) * [1 - (1 + i)^n]/[1 - (1 + i)]
* = PV * (1 + i)^n + PMT * (1 + iX) * [1 - (1 + i)^n]/[-i]
* = PV * (1 + i)^n + PMT * (1 + iX) * [(1 + i)^n - 1]/i
*
* The formaula for PV[n] can be proven using mathematical induction.
*
* or:
*
* PV * (1 + i)^n + PMT * [(1 + i)^n - 1]/i - PV[n] = 0
*
* If after n payments, the remaining balance is repaid as a lump
* sum, the lump sum is known as the Future Value, FV[n]. Since
* FV[n] is negative if paid and positive if received, FV[n] is the
* negative of PV[n]. Since n is assumed to be the last payment,
* FV[n] will be shortened to simply FV.
*
* Setting: FV = -PV[N]
*
* 1) PV*(1 + i)^n + PMT*(1 + iX)*[(1 + i)^n - 1]/i + FV = 0
*
* Up to this point, we have said nothing about the value of
* PMT. PMT can be any value mutually agreed upon by the lender and
* the borrower. From the equation for PV[1]:
*
* PV[1] = PV + (PMT + (PV + X * PMT) * i),
*
* Several things can be said about PMT.
*
* 1. If PMT = PV * i, and X = 0 (end of period payments):
*
* The payment is exactly equal to the interest due and PV[1] =
* PV. In this case, the borrower must make larger future
* payments to reduce the balance due, or make a single payment,
* after some agreed upon number of payments, with PMT = PV to
* completely pay off the loan. This is an interest only payment
* with a balloon payment at the end.
*
* 2. If PMT < PV * i, and X = 0
*
* The payment is insufficient to cover even the interest charged
* and the balance due grows
*
* 3. If PMT > PV * i, and X = 0
*
* The payment is sufficient to cover the interest charged with a
* residual amount to be applied to reduce the balance due. The
* larger the residual amount, the faster the loan is repaid. For
* most mortgages or other loans made today, the lender and
* borrower agree upon a certain number of repayment periods and
* the interest to be charged per payment period. The interest
* may be multiplied by 12 and stated as an annual interest
* rate. Then the lender and borrower want to compute a periodic
* payment, PMT, which will reduce the balance due to zero after
* the agreed upon number of payment have been made. If N is the
* agreed upon number of periodic payments, then we want to use:
*
* PV * (1 + i)^N + PMT*(1 +iX)*[(1 + i)^N - 1]/i + FV = 0
*
* with FV = 0 to compute PMT:
*
* PMT = -[PV * i * (1 + i)^(N - X)]/[(1 + i)^N - 1]
*
* The value of PMT computed will reduce the balance due to zero
* after N periodic payments.
*
* ****************************************************************************
*
*
* With a simple alegebraic re-arrangement, The financial Equation becomes:
*
* 2) [PV + PMT*(1 + iX)/i][(1 + i)^n - 1] + PV + FV = 0
*
* or
*
* 3) (PV + C)*A + PV + FV = 0
*
* where:
* 4) A = (1 + i)^n - 1
*
* 5) B = (1 + iX)/i
*
* 6) C = PMT*B
*
* The form of equation 3) simplifies the calculation procedure for all five
* variables, which are readily solved as follows:
*
* 7) n = ln[(C - FV)/(C + PV)]/ln((1 + i)
*
* 8) PV = -[FV + A*C]/(A + 1)
*
* 9) PMT = -[FV + PV*(A + 1)]/[A*B]
*
* 10) FV = -[PV + A*(PV + C)]
*
* Equations 4), 5) and 6) are computed by functions:
*
* _A
* _B
* _C
*
* respectively. Equations 7), 8), 9) and 10) are computed by functions:
*
* _N
* _PV
* _PMT
* _FV
*
* respectively.
*
* The solution for interest is broken into two cases:
*
* PMT == 0
* i = [FV/PV]^(1/n) - 1
*
* PMT != 0
*
* Since equation 3) cannot be solved explicitly for i in this
* case, an iterative technique must be employed. Newton's
* method, using exact expressions for the function of i and its
* derivative, are employed. The expressions are:
*
* 12) i[k+1] = i[k] - f(i[k])/f'(i[k])
* where: i[k+1] == (k+1)st iteration of i
* i[k] == kth iteration of i
* and:
*
* 13) f(i) = A*(PV+C) + PV + FV
*
* 14) f'(i) = n*D*(PV+C) - (A*C)/i
*
* 15) D = (1 + i)^(n-1) = (A+1)/(1+i)
*
* To start the iterative solution for i, an initial guess must be made
* for the value of i. The closer this guess is to the actual value,
* the fewer iterations will have to be made, and the greater the
* probability that the required solution will be obtained. The initial
* guess for i is obtained as follows:
*
* if PMT*FV >= 0, then PV case
* if PMT*FV < 0, then FV case
*
* PV case:
* | n*PMT + PV + FV |
* 16) i[0] = | ----------------|
* | n*PV |
*
* = abs[(n*PMT + PV + FV)/(n*PV)]
*
* FV case:
* a) PV != 0
*
* | FV - n*PMT |
* 17) i[0] = |---------------------------|
* | 3*[PMT*(n-1)^2 + PV - FV] |
*
* = abs[(FV-n*PMT)/(3*(PMT*(n-1)^2+PV-FV))]
* b) PV == 0
*
* | FV + n*PMT |
* 18) i[0] = |---------------------------|
* | 3*[PMT*(n-1)^2 + PV - FV] |
*
* = abs[(FV+n*PMT)/(3*(PMT*(n-1)^2+PV-FV))]
*
* ****************************************************************************
* Constant payment to principal loan
*
* In this loan, each total payment is different, with each
* succeeding payment less than the preceding payment. Each payment
* is the total of the constant amount to the principal plus the
* interest for the period. The constant payment to the principal is
* computed as:
*
* C = -PV / N
*
* Where PV is the loan amount to be repaid in N payments
* (periods). Note that the constant payment to principal could be
* any value agreed to by the two parties involved.
*
* Thus the principal after the first payment is:
* PV[1] = PV[0] + C = PV + C
* after the second payment, the principal is:
* PV[2] = PV[1] + C = PV[0] + 2C
* In general, the remaining principal after n payments is:
* PV[n] = PV[0] + nC = PV + nC
*
* If the effective interest per payment period is i, then the
* interest for the first payment is:
*
* I[1] = -i*PV[0] = -i*PV
* and for the second:
* I[2] = -i * PV[1]
* and in general, for the n'th payment the interest is:
* I[n] = -i * PV[n-1]
* = -i * (PV + (n-1)C)
* The total payment for any period, n, is:
* P[n] = C + I[n]
* = C + i * (PV + (n-1)C)
* = C(1 + i) - i * (PV + nC)
* The total interest paid to period n is:
* T[n] = I[1] + I[2] + I[3] + ... + I[n]
* T[n] = sum(j = 1 to n: I[j])
* T[n] = sum(j = 1 to n: -i * (PV + (j-1)C))
* T[n] = sum(j=1 to n: -i*PV) + sum(j=1 to n: iC) + sum(j=1 to n: -iCj)
* T[n] = -i*n*PV + i*n*C - i*C*sum(j=1 to n:j)
* sum(j=1 to n:j) = n(n+1)/2
* T[n] = -i*n*(PV + C) - i*C*n(n+1)/2
* T[n] = -i*n*(PV + (C*(n - 1)/2))
*
* Note: substituing for C = -PV/N, in the equations for PV[n], I[n],
* P[n], and T[n] would give the following equations:
*
* PV[n] = PV*(1 - n/N)
* I[n] = -i*PV*(1 + N - n)/N
* P[n] = -i*PV*(2 + N - n)/N
* T[n] = -i*n*PV*(2*N - n + 1)/(2*N)
*
* Using these equations for the calculations would eliminate the
* dependence on C, but only if C is always defined as above and
* would eliminate the possibility of another value for C. If the
* value of C was less than -PV/N then a balloon payment would be
* due at the final payment and this is a possible alternative for
* some people.
*
* ****************************************************************************
*
* Amortization Schedules.
*
* Financial Transactions have an effective Date, ED, and an Initial Payment
* Date, IP. ED may or may not be the same as IP, but IP is always the same
* or later than ED. Most financial transaction calculators assume that
* IP is equal to ED for beginning of period payments or at the end of the
* first payment period for end of period payments.
*
* This is not always true. IP may be delayed for financial reasons
* such as cash flow or accounting calendar. The subsequent payments
* then follow the agreed upon periodicity. Since money has a time
* value, the "delayed" IP must be accounted for. Computing an
* "Effective PV", pve, is one means of handling a delayed IP.
*
* EDj == the Julian Day Number of ED, and
* IPj == the Julian Day Number of IP in the following.
*
* pve is be computed as:
*
* pve = pv*(1 + i)^(s*PF/d*CF)
*
* Where: d = length of the payment period in days, and
* s = IPj - EDj - d*X
*
* Computing an amortization Schedule for a given financial transaction is
* simply applying the basic equation iteratively for each payment period:
*
* PV[n] = PV[n-1] + (PMT + (PV[n-1] + X * PMT) * i)
*
* At the end of each iteration, PV[n] is rounded to the nearest cent. For
* each payment period, the interest due may be computed separately as:
*
* ID[n] = (PMT + (PV[n-1] + X * PMT) * i)
*
* and rounded to the nearest cent. PV[n] then becomes:
*
* PV[n] = PV[n-1] + PMT + ID[n]
*
* For those cases where a yearly summary only is desired, it is not
* necessary to compute each transaction for each payment period,
* rather the PV may be computed for the beginning of each year,
* PV[yr], and the FV computed for the end of the year, FV[yr]. The
* interest paid during the year is the computed as:
*
* ID[yr] = (NP * PMT) + PV[yr] + FV[yr]
*
* Since the final payment may not be equal to the periodic payment,
* the final payment must be computed separately as follows. Two
* derivations are given below for the final payment equation. Both
* derivations are given below since one or the other may be clearer
* to some readers. Both derivations are essentially the same, they
* just have different starting points. The first is the fastest.
*
* 1) final_pmt == final payment @ payment n == int(n)
* from above the basic financial equation:
* PV[n] = PV[n-1]*(1 + i) + final_pmt * (1 + iX),
* i == effective interest rate
*
* solving for final_pmt, we have:
*
* final_pmt * (1 + iX) = PV[n] - PV[n-1]*(1 + i)
* = FV[n-1]*(1 + i) - FV[n]
* final_pmt = FV[n-1]*(1+i)/(1 + iX) - FV[n]/(1 + iX)
*
* final_pmt = FV[n-1]*(1 + i) - FV[n],
* for X == 0, end of period payments
*
* = FV[n-1] - FV[n]/(1 + i),
* for X == 1, beginning of period payments
*
* 2) final_pmt == final payment @ payment n == int(n)
* i[n] == interest due @ payment n
* i[n] = (PV[n-1] + X * final_pmt) * i, i == effective interest rate
* = (X * final_pmt - FV[n]) * i
*
* Now the final payment is the sum of the interest due, plus
* the present value at the next to last payment plus any
* residual future value after the last payment:
*
* final_pmt = -i[n] - PV[n-1] - FV[n]
* = FV[n-1] - i[n] - FV[n]
* = FV[n-1] - (X *final_pmt - FV[n-1])*i - FV[n]
* = FV[n-1]*(1 + i) - X*final_pmt*i - FV[n]
*
* solving for final_pmt:
* final_pmt*(1 + iX) = FV[n-1]*(1 + i) - FV[n]
* final_pmt = FV[n-1]*(1 + i)/(1 + iX) - FV[n]/(1 + iX)
*
* final_pmt = FV[n-1]*(1 + i) - FV[n],
* for X == 0, end of period payments
*
* = FV[n-1] - FV[n]/(1 + i),
* for X == 1, beginning of period payments
*
*============================================================================
*
* The amortization schedule is computed for four different situations:
*
* 1) The original financial data is used. This ignores any possible
* agjustment to the Present value due to any delay in the initial
* payment. This is quite common in mortgages where end of period
* payments are used and the first payment is scheduled for the end
* of the first whole period, i.e., any partial payment period from
* ED to the beginning of the next payment period is ignored.
*
* 2) The original periodic payment is used, the Present Value is
* adjusted for the delayed Initial Payment. The total number of
* payments remains the same. The final payment is adjusted to bring
* the balance into agreement with the agreed upon final Future
* Value.
*
* 3) A new periodic payment is computed based upon the adjusted
* Present Value, the agreed originally upon number of total
* payments and the agreed upon Future Value. The new periodic
* payments are computed to minimize the final payment in accordance
* with the Future Value after the last payment.
*
* 4) The original periodic payment is retained and a new number of
* total payments is computed based upon the adjusted Present Value
* and the agreed upon Future Value.
*
* The amortization schedule may be computed and displayed in three manners:
*
* 1. The payment *, interest paid, principal paid and remaining PV
* for each payment period are computed and displayed. At the end of
* each year a summary is computed and displayed and the total
* interest paid is diplayed at the end.
*
* 2. A summary is computed and displayed for each year. The
* interest paid during the year is computed and displayed as well
* as the remaining balance at years end. The total interest paid
* is diplayed at the end.
*
* 3. An amortization schedule is computed for a common method of
* advanced payment of principal is computed and displayed. In this
* amortization, the principal for the next payment is computed and
* added into the current payment. This method will cut the number
* of total payments in half and will cut the interest paid almost
* in half. For mortgages, this method of prepayment has the
* advantage of keeping the total payments small during the initial
* payment periods The payments grow until the last payment period
* when presumably the borrower can afford larger payments.
*
* ===========================================================================
* NOTE: For Payment Frequencies, PF, semi-monthly or less, i.e., PF
* == 12 or PF == 24, a 360 day calendar year and 30 day month are
* used. For Payment Frequencies, PF, greater than semi-monthly, PF
* > 24, the actual number of days per year and per payment period
* are used. The actual values are computed using the built-in
* 'julian_day_number' function
*
* ****************************************************************************
*
* Note: in the following examples, the user input is preceded by the
* prompt "<>". The result of evaluating the input expression is then
* displayed. I have taken the liberty of including comments in the
* example input/output sessions by preceding with ' *'. Thus, for
* the line: <>n=5 *set number of periods the comment that setting the
* number of periods is not really input and the true input is only:
* <>n=5
*
* Example 1: Simple Interest
* Find annual simple interest rate (%) for an $800 loan to be repayed at the
* end of one year with a single payment of $896.
* <>d
* <>CF=PF=1
* 1.00
* <>n=1
* 1.00
* <>pv=-800
* -800.00
* <>fv=896
* 896.00
* <>I
* 12.00
*
* Example 2: Compound Interest
* Find the future value of $800 after one year at a nominal rate of 12%
* compounded monthly. No payments are specified, so the payment frequency is
* set equal to the compounding frequency at the default values.
* <>d
* <>n=12
* 12.00
* <>i=12
* 12.00
* <>pv=-800
* -800.00
* <>FV
* 901.46
*
* Example 3: Periodic Payment:
* Find the monthly end-of-period payment required to fully amortize the loan
* in Example 2. A fully amortized loan has a future value of zero.
* <>fv=0
* 0.00
* <>PMT
* 71.08
*
* Example 4: Conventional Mortgage
*
* Find the number of monthly payments necessary to fully amortize a
* loan of $100,000 at a nominal rate of 13.25% compounded monthly, if
* monthly end-of-period payments of $1125.75 are made.
*
* <>d
* <>i=13.25
* 13.25
* <>pv=100000
* 100,000.00
* <>pmt=-1125.75
* -1,125.75
* <>_N(i,pv,pmt,fv,CF,PF,disc,bep)
* 360.10
* <>N
* 360
*
* Example 5: Final Payment
* Using the data in example 4, find the amount of the final payment if n is
* changed to 360. The final payment will be equal to the regular payment plus
* any balance, future value, remaining at the end of period number 360.
* <>n=360
* 360.00
* <>FV
* -108.87
* <>pmt+fv
* -1,234.62
*
* Using the data from this loan, compute the amortization schedule
* when the Effective date of the loan is June 6, 1996 and the
* initial payment is made on August 1, 1996. Ignore any change in
* the PV due to the delayed initial payment caused by the partial
* payment period from June 6 to July 1.
*
* <>ED = 06/06/1996
* Effective Date set: 06/06/1996 ( 2450241 )
* <>IP = 08/01/1996
* Initial Payment Date set: 08/01/1996 ( 2450297 )
* <>a
* Effective Date: 06/06/96
* Initial Payment Date: 08/01/96
* The amortization options are:
* The Old Present Value (pv) was: 100,000.00
* The Old Periodic Payment (pmt) was: -1,125.75
* The Old Future Value (fv) was: -108.87
* 1: Amortize with Original Transaction Values
* and balloon final payment: -1,125.75
*
* The New Present Value (pve) is: 100,919.30
* The New Periodic Payment (pmt) is: -1,136.10
* 2: Amortize with Original Periodic Payment
* and balloon final payment: -49,023.68
* 3: Amortize with New Periodic Payment
* and balloon final payment: -1,132.57
* 4: Amortize with Original Periodic Payment,
* new number of total payments (n): 417
* and final payment: -2,090.27
*
* Enter choice 1, 2, 3 or 4: <>
*
* Press '1'
* Amortization Schedule:
* Yearly, y, per Payment, p, or Advanced Payment, a, Amortization
* Enter choice y, p or a:
* <>
*
* Press 'y'
* Enter Filename for Amortization Schedule.
* (null string uses Standard Output):
* Press enter to display output on screen
*
* Amortization Table
* Effective Date: Thu Jun 06 00:00:00 1996
* Initial Payment Date: Thu Aug 01 00:00:00 1996
* Compounding Frequency per year: 12
* Payment Frequency per year: 12
* Compounding: Discrete
* Payments: End of Period
* Payments (359): -1,125.75
* Final payment: -1,125.75
* Nominal Annual Interest Rate: 13.25
* Effective Interest Rate Per Payment Period: 0.0110417
* Present Value: 100,000.00
* Year Interest Ending Balance
* 1996 -5,518.42 -99,889.67
* 1997 -13,218.14 -99,598.81
* 1998 -13,177.17 -99,266.98
* 1999 -13,130.43 -98,888.41
* 2000 -13,077.11 -98,456.52
* 2001 -13,016.28 -97,963.80
* 2002 -12,946.88 -97,401.68
* 2003 -12,867.70 -96,760.38
* 2004 -12,777.38 -96,028.76
* 2005 -12,674.33 -95,194.09
* 2006 -12,556.76 -94,241.85
* 2007 -12,422.64 -93,155.49
* 2008 -12,269.63 -91,916.12
* 2009 -12,095.06 -90,502.18
* 2010 -11,895.91 -88,889.09
* 2011 -11,668.70 -87,048.79
* 2012 -11,409.50 -84,949.29
* 2013 -11,113.78 -82,554.07
* 2014 -10,776.41 -79,821.48
* 2015 -10,391.53 -76,704.01
* 2016 -9,952.43 -73,147.44
* 2017 -9,451.49 -69,089.93
* 2018 -8,879.99 -64,460.92
* 2019 -8,227.99 -59,179.91
* 2020 -7,484.16 -53,155.07
* 2021 -6,635.56 -46,281.63
* 2022 -5,667.43 -38,440.06
* 2023 -4,562.94 -29,494.00
* 2024 -3,302.89 -19,287.89
* 2025 -1,865.36 -7,644.25
* 2026 -236.00 -108.87
*
* Total Interest: -305,270.00
*
* NOTE: The amortization table leaves the FV as it was when the amortization
* function was entered. Thus, a balance of 108.87 is due at the end of the
* table. To completely pay the loan, set fv to 0.0:
* <>fv=0
* 0.0
* <>a
* Effective Date: 06/06/96
* Initial Payment Date: 08/01/96
* The amortization options are:
* The Old Present Value (pv) was: 100,000.00
* The Old Periodic Payment (pmt) was: -1,125.75
* The Old Future Value (fv) was: 0.00
* 1: Amortize with Original Transaction Values
* and balloon final payment: -1,234.62
*
* The New Present Value (pve) is: 100,919.30
* The New Periodic Payment (pmt) is: -1,136.12
* 2: Amortize with Original Periodic Payment
* and balloon final payment: -49,132.55
* 3: Amortize with New Periodic Payment
* and balloon final payment: -1,148.90
* 4: Amortize with Original Periodic Payment,
* new number of total payments (n): 417
* and final payment: -2,199.14
*
* Enter choice 1, 2, 3 or 4: <>
* Press '1'
* Amortization Schedule:
* Yearly, y, per Payment, p, or Advanced Payment, a, Amortization
* Enter choice y, p or a:
* <>
* Press 'y'
* Enter Filename for Amortization Schedule.
* (null string uses Standard Output):
* Press enter to display output on screen
*
* Amortization Table
* Effective Date: Thu Jun 06 00:00:00 1996
* Initial Payment Date: Thu Aug 01 00:00:00 1996
* Compounding Frequency per year: 12
* Payment Frequency per year: 12
* Compounding: Discrete
* Payments: End of Period
* Payments (359): -1,125.75
* Final payment: -1,234.62
* Nominal Annual Interest Rate: 13.25
* Effective Interest Rate Per Payment Period: 0.0110417
* Present Value: 100,000.00
* Year Interest Ending Balance
* 1996 -5,518.42 -99,889.67
* 1997 -13,218.14 -99,598.81
* 1998 -13,177.17 -99,266.98
* 1999 -13,130.43 -98,888.41
* 2000 -13,077.11 -98,456.52
* 2001 -13,016.28 -97,963.80
* 2002 -12,946.88 -97,401.68
* 2003 -12,867.70 -96,760.38
* 2004 -12,777.38 -96,028.76
* 2005 -12,674.33 -95,194.09
* 2006 -12,556.76 -94,241.85
* 2007 -12,422.64 -93,155.49
* 2008 -12,269.63 -91,916.12
* 2009 -12,095.06 -90,502.18
* 2010 -11,895.91 -88,889.09
* 2011 -11,668.70 -87,048.79
* 2012 -11,409.50 -84,949.29
* 2013 -11,113.78 -82,554.07
* 2014 -10,776.41 -79,821.48
* 2015 -10,391.53 -76,704.01
* 2016 -9,952.43 -73,147.44
* 2017 -9,451.49 -69,089.93
* 2018 -8,879.99 -64,460.92
* 2019 -8,227.99 -59,179.91
* 2020 -7,484.16 -53,155.07
* 2021 -6,635.56 -46,281.63
* 2022 -5,667.43 -38,440.06
* 2023 -4,562.94 -29,494.00
* 2024 -3,302.89 -19,287.89
* 2025 -1,865.36 -7,644.25
* 2026 -344.87 0.00
*
* Total Interest: -305,378.87
*
* Example 6: Balloon Payment
* On long term loans, small changes in the periodic payments can generate
* large changes in the future value. If the monthly payment in example 5 is
* rounded down to $1125, how much addtional (balloon) payment will be due
* with the final regular payment.
* <>pmt=-1125
* -1,125
* <>FV
* -3,579.99
*
* Example 7: Canadian Mortgage
* Find the monthly end-of-period payment necessary to fully amortize a 25 year
* $85,000 loan at 11% compounded semi-annually.
* <>d
* <>CF=2
* 2.00
* <>n=300
* 300.00
* <>i=11
* 11.00
* <>pv=85000
* 85,000.00
* <>PMT
* -818.15
*
* Example 8: European Mortgage
* The "effective annual rate (EAR)" is used in some countries (especially
* in Europe) in lieu of the nominal rate commonly used in the United States
* and Canada. For a 30 year $90,000 mortgage at 14% (EAR), compute the monthly
* end-of-period payments. When using an EAR, the compounding frequency is
* set to 1.
* <>d
* <>CF=1
* 1.00
* <>n=30*12
* 360.00
* <>i=14
* 14.00
* <>pv=90000
* 90,000.00
* <>PMT
* -1,007.88
*
* Example 9: Bi-weekly Savings
* Compute the future value, fv, of bi-weekly savings of $100 for 3 years at a
* nominal annual rate of 5.5% compounded daily. (Set payment to
* beginning-of-period, bep = TRUE)
* <>d
* <>bep=TRUE
* 1.00
* <>CF=365
* 365.00
* <>PF=26
* 26.00
* <>n=3*26
* 78.00
* <>i=5.5
* 5.50
* <>pmt=-100
* -100.00
* <>FV
* 8,489.32
*
* Example 10: Present Value - Annuity Due
* What is the present value of $500 to be received at the beginning of each
* quarter over a 10 year period if money is being discounted at 10% nominal
* annual rate compounded monthly?
* <>d
* <>bep=TRUE
* 1.00
* <>PF=4
* 4.00
* <>n=4*10
* 40.00
* <>i=10
* 10.00
* <>pmt=500
* 500.00
* <>PV
* -12,822.64
*
* Example 11: Effective Rate - 365/360 Basis
* Compute the effective annual rate (%APR) for a nominal annual rate of 12%
* compounded on a 365/360 basis used by some Savings & Loan Associations.
* <>d
* <>n=365
* 365.00
* <>CF=365
* 365.00
* <>PF=360
* 360.00
* <>i=12
* 12.00
* <>pv=-100
* -100.00
* <>FV
* 112.94
* <>fv+pv
* 12.94
*
* Example 12: Mortgage with "Points"
*
* What is the true APR of a 30 year, $75,000 loan at a nominal rate
* of 13.25% compounded monthly, with monthly end-of-period payments,
* if 3 "points" are charged? The pv must be reduced by the dollar
* value of the points and/or any lenders fees to establish an
* effective pv. Because payments remain the same, the true APR will
* be higher than the nominal rate. Note, first compute the payments
* on the pv of the loan amount.
*
* <>d
* <>CF=PF=1
* 1.00
* <>n=30*12
* 360.00
* <>i=13.25/12
* 1.10
* <>pv=75000
* 75,000.00
* <>PMT
* -844.33
* <>pv -= pv*.03
* 72,750.00
* <>CF=PF=12
* 12.00
* <>I
* 13.69
*
* Example 13: Equivalent Payments
* Find the equivalent monthly payment required to amortize a 20 year $40,000
* loan at 10.5% nominal annual rate compounded monthly, with 10 annual
* payments of $5029.71 remaining. Compute the pv of the remaining annual
* payments, then change n, the number of periods, and the payment frequency,
* PF, to a monthly basis and compute the equivalent monthly pmt.
* <>d
* <>PF=1
* 1.00
* <>n=10
* 10.00
* <>i=10.5
* 10.50
* <>pmt=-5029.71
* -5,029.71
* <>PV
* 29,595.88
* <>PF=12
* 12.00
* <>n=120
* 120.00
* <>PMT
* -399.35
*
* Example 14: Perpetuity - Continuous Compounding
* If you can purchase a single payment annuity with an initial investment of
* $60,000 that will be invested at 15% nominal annual rate compounded
* continuously, what is the maximum monthly return you can receive without
* reducing the $60,000 principal? If the principal is not disturbed, the
* payments can go on indefinitely (a perpetuity). Note that the term,n, of
* a perpetuity is immaterial. It can be any non-zero value.
* <>d
* <>disc=FALSE
* 0.00
* <>n=12
* 12.00
* <>CF=1
* 1.00
* <>i=15
* 15.00
* <>fv=60000
* 60,000.00
* <>pv=-60000
* -60,000.00
* <>PMT
* 754.71
*
* references:
* 1. PPC ROM User's Manual
* pages 148 - 164
*
*/
#include <time.h>
#include <stdio.h>
#include <glib.h>
#include <math.h>
#if defined(G_OS_WIN32) && !defined(_MSC_VER)
#include <pow.h>
#endif
#include <string.h>
#include <stdlib.h>
#define FIN_STATICS
#include "finvar.h"
#include "finproto.h"
#include "fin_static_proto.h"
/* return 'x' rounded to 'places' past decimal if 'places' < 0, return
* 'x' */
static double
rnd (double x, unsigned places)
{
double r;
char buf[50]; /* make buffer large enough */
sprintf (buf, "%.*f", (int) places, x);
r = strtod(buf, NULL);
return r;
} /* rnd */
/* return absolute value of 'x' this function is provided by a macro
* in C */
static double
dabs (double x)
{
return (x >= 0.0) ? x : -x;
} /* dabs */
/* Compute constant used in calculations */
static double
_A (double eint, unsigned per)
{
return pow ((1.0 + eint), (double) per) - 1.0;
} /* _A */
/* Compute constant used in calculations */
static double
_B (double eint, unsigned beg)
{
/* if eint == 0.0, all processing _must_ stop or
a recursive loop will start. */
g_return_val_if_fail(eint != 0.0, 0.0);
return (1.0 + eint * (double) beg) / eint;
} /* _B */
/* Compute constant used in calculations */
static double
_C (double eint, double pmt, unsigned beg)
{
g_return_val_if_fail(eint != 0.0, 0.0);
return pmt * _B(eint, beg);
} /* _C */
/* compute Number of Periods from preset data */
unsigned
fi_calc_num_payments (fi_ptr fi)
{
return fi->npp =
(unsigned)
rnd (_fi_calc_num_payments
(fi->ir, fi->pv, fi->pmt, fi->fv, fi->CF, fi->PF, fi->disc, fi->bep),
0);
} /* fi_calc_num_payments */
/* Compute number of periods from:
* 1. Nominal Interest
* 2. Present Value
* 3. Periodic Payment
* 4. Future Value
*/
double
_fi_calc_num_payments (double nint, /* nominal interest rate */
double pv, /* present value */
double pmt, /* periodic payment */
double fv, /* future value */
unsigned CF, /* compounding frequency */
unsigned PF, /* payment frequency */
unsigned disc, /* discrete/continuous compounding */
unsigned bep) /* beginning/end of period payment */
{
double eint = eff_int (nint / 100.0, CF, PF, disc);
double CC = _C (eint, pmt, bep);
CC = (CC - fv) / (CC + pv);
return (CC > 0.0) ? log (CC) / log (1.0 + eint) : 0.0;
} /* _fi_calc_num_payments */
/* compute Interest from preset data */
double
fi_calc_interest (fi_ptr fi)
{
if (fi->npp)
fi->ir = _fi_calc_interest (fi->npp, fi->pv, fi->pmt, fi->fv,
fi->CF, fi->PF, fi->disc, fi->bep);
return fi->ir;
} /* fi_calc_interest */
double ratio = 1e4; /* ratio used in iterative solution for interest */
/* Compute Nominal Interest from:
* 1. Number of periods
* 2. Present Value
* 3. Periodic Payment
* 4. Future Value
*/
double
_fi_calc_interest (unsigned per,/* number of periods */
double pv, /* present value */
double pmt, /* periodic payment */
double fv, /* future value */
unsigned CF, /* compounding frequency */
unsigned PF, /* payment frequency */
unsigned disc, /* discrete/continuous compounding */
unsigned bep) /* beginning/end of period payment */
{
double eint;
double a, dik;
int ri;
if (pmt == 0.0)
eint = pow ((dabs (fv) / dabs (pv)), (1.0 / (double) per)) - 1.0;
else
{
if ((pmt * fv) < 0.0)
{
if (pv)
a = -1.0;
else
a = 1.0;
eint =
dabs ((fv + a * (double) per * pmt) /
(3.0 *
(((double) per - 1.0) * ((double) per - 1.0) * pmt + pv -
fv)));
}
else
{
if ((pv * pmt) < 0.0)
{
eint = dabs (((double) per * pmt + pv + fv) / ((double) per * pv));
}
else
{
a = dabs (pmt / (dabs (pv) + dabs (fv)));
eint = a + 1.0 / (a * (double) per * (double) per * (double) per);
}
}
do
{
dik =
fi (per, eint, pv, pmt, fv, bep) / fip (per, eint, pv, pmt, fv, bep);
eint -= dik;
(void) modf (ratio * (dik / eint), &a);
ri = (unsigned) a;
}
while (ri);
} /* endif */
return 100.0 * nom_int (eint, CF, PF, disc);
} /* _fi_calc_interest */
/* compute Present value from preset data */
double
fi_calc_present_value (fi_ptr fi)
{
return fi->pv =
rnd (_fi_calc_present_value
(fi->npp, fi->ir, fi->pmt, fi->fv, fi->CF, fi->PF, fi->disc,
fi->bep), fi->prec);
} /* fi_calc_present_value */
/* Compute Present Value from:
* 1. Number of periods
* 2. Nominal Interest
* 3. Periodic Payment
* 4. Future Value
*/
double
_fi_calc_present_value (unsigned per, /* number of periods */
double nint, /* nominal interest rate */
double pmt, /* periodic payment */
double fv, /* future value */
unsigned CF, /* compounding frequency */
unsigned PF, /* payment frequency */
unsigned disc, /* discrete/continuous compounding */
unsigned bep) /* beginning/end of period payment */
{
double eint = eff_int (nint / 100.0, CF, PF, disc);
double AA = _A (eint, per);
double CC = _C (eint, pmt, bep);
return -(fv + (AA * CC)) / (AA + 1.0);
} /* _fi_calc_present_value */
/* compute Periodic Payment from preset data */
double
fi_calc_payment (fi_ptr fi)
{
return fi->pmt =
rnd (_fi_calc_payment
(fi->npp, fi->ir, fi->pv, fi->fv, fi->CF, fi->PF, fi->disc, fi->bep),
fi->prec);
} /* fi_calc_payment */
/* Compute Periodic Payment from:
* 1. Number of periods
* 2. Nominal Interest
* 3. Present Value
* 4. Future Value
*/
double
_fi_calc_payment (unsigned per, /* number of periods */
double nint, /* nominal interest rate */
double pv, /* present value */
double fv, /* future value */
unsigned CF, /* compounding frequency */
unsigned PF, /* payment frequency */
unsigned disc,/* discrete/continuous compounding */
unsigned bep) /* beginning/end of period payment */
{
double eint = eff_int (nint / 100.0, CF, PF, disc);
double AA = _A (eint, per);
double BB = _B (eint, bep);
g_return_val_if_fail(BB != 0.0, 0.0);
return -(fv + pv * (AA + 1.0)) / (AA * BB);
} /* _fi_calc_payment */
/* compute Future Value from preset data */
double
fi_calc_future_value (fi_ptr fi)
{
return fi->fv =
rnd (_fi_calc_future_value
(fi->npp, fi->ir, fi->pv, fi->pmt, fi->CF, fi->PF, fi->disc,
fi->bep), fi->prec);
} /* fi_calc_future_value */
/* Compute Future Value from:
* 1. Number of periods
* 2. Nominal Interest
* 3. Present Value
* 4. Periodic Payments
*/
double
_fi_calc_future_value (unsigned per, /* number of periods */
double nint, /* nominal interest rate */
double pv, /* present value */
double pmt, /* periodic payment */
unsigned CF, /* compounding frequency */
unsigned PF, /* payment frequency */
unsigned disc, /* discrete/continuous compounding */
unsigned bep) /* beginning/end of period payment */
{
double eint = eff_int (nint / 100.0, CF, PF, disc);
double AA = _A (eint, per);
double CC = _C (eint, pmt, bep);
return -(pv + AA * (pv + CC));
} /* _fi_calc_future_value */
/* compute Nominal Interest Rate from Effective Interest Rate */
static double
nom_int (double eint, unsigned CF, unsigned PF, unsigned disc)
{
double nint;
if (disc)
{
if (CF == PF)
{
nint = CF * eint;
}
else
{
nint = CF * (pow ((1.0 + eint), ((double) PF / (double) CF)) - 1.0);
} /* * endif */
}
else
nint = log (pow (1.0 + eint, PF));
return nint;
} /* nom_int */
/* Compute Effective Interest Rate from Nominal Interest Rate */
static double
eff_int (double nint, unsigned CF, unsigned PF, unsigned disc)
{
double eint;
if (disc)
{
if (CF == PF)
{
eint = nint / (double) CF;
}
else
{
eint =
pow ((1.0 + nint / (double) CF), ((double) CF / (double) PF)) - 1.0;
} /* endif */
}
else
eint = exp (nint / (double) PF) - 1.0;
return eint;
} /* eff_int */
/* calculation used in interest computation */
static double
fi (unsigned per, double eint, double pv, double pmt, double fv, unsigned bep)
{
return _A (eint, per) * (pv + _C (eint, pmt, bep)) + pv + fv;
} /* fi */
/* calculation used in interest computation
*/
static double
fip (unsigned per, double eint, double pv, double pmt, double fv, unsigned bep)
{
double AA = _A (eint, per);
double CC = _C (eint, pmt, bep);
double D = (AA + 1.0) / (1.0 + eint);
g_return_val_if_fail(CC != 0.0, 0.0);
return (double) per * (pv + CC) * D - (AA * CC) / eint;
} /* fip */
void
set_default (fi_ptr fi)
{
/* flag whether accrueing interest at beginning or end of period
* FALSE --> end
* TRUE --> beginning
* default to end of period payment s
*/
fi->bep = FALSE;
/* flag for discrete or continuous interest
* TRUE --> discrete
* FALSE --> continuous
* default to discrete interest
*/
fi->disc = TRUE;
/* set compounding, CF, and payment, PF, frequency per year
* default to monthly payments and compounding
*/
fi->CF = fi->PF = 12;
/* standard loan quantities:
* number of periods: n
*/
fi->npp = 0;
/* annual interest: i
*/
fi->ir = 0.0;
/* Present Value: pv
*/
fi->pv = 0.0;
/* Payment: pmt
*/
fi->pmt = 0.0;
/* Future Value: fv
*/
fi->fv = 0.0;
} /* set_default */
/* compute Julian Day Number from calendar date
*/
unsigned long
julian_day_number (unsigned year, unsigned month, unsigned day)
{
/* Gregorian/Julian Calendar Flag.
* TRUE == Julian
* FALSE == Gregorian
*/
unsigned gregorian = TRUE; /* assume we are dealing with current dates */
double yr;
double pfac = 0.6;
unsigned long ljdn;
yr = year + (month - 3.0) / 12.0;
ljdn = (long) (367.0 * yr + pfac) - (2 * (long) (yr)) + (long) (yr / 4.0)
+ (long) day + 1721117L;
if (gregorian)
ljdn += -(long) (yr / 100.0) + (long) (yr / 400.0) + 2;
return ljdn;
} /* julian_day_number */
amort_sched_ptr
Amortization_init (amort_sched_ptr amortsched)
{
unsigned n = amortsched->n;
double nint = amortsched->nint;
double pv = amortsched->pv;
double pmt = amortsched->pmt;
double fv = amortsched->fv;
double eint;
double new_pmt;
double pve;
unsigned CF = amortsched->CF;
unsigned PF = amortsched->PF;
unsigned disc = amortsched->disc;
unsigned bep = amortsched->bep;
unsigned new_n;
unsigned prec = amortsched->prec;
unsigned long s,
d,
days_to_yr_end,
Eff_Date_jdn =
julian_day_number (amortsched->year_E, amortsched->month_E,
amortsched->day_E), Init_Date_jdn =
julian_day_number (amortsched->year_I, amortsched->month_I,
amortsched->day_I);
amortsched->Eff_Date_jdn = Eff_Date_jdn;
amortsched->Init_Date_jdn = Init_Date_jdn;
amortsched->yday_E =
Eff_Date_jdn - julian_day_number (amortsched->year_E, 1, 1);
amortsched->yday_I =
Init_Date_jdn - julian_day_number (amortsched->year_I, 1, 1);
amortsched->eint = eint = eff_int (nint / 100.0, CF, PF, disc);
amortsched->fv_case = dabs (fv) > dabs (pv);
amortsched->bp = bep ? 1.0 : 0.0;
if (PF > 24)
{
/* Payment frequency per year greater than bi-monthly
* use actual number of days
*/
s = Init_Date_jdn - Eff_Date_jdn;
days_to_yr_end =
julian_day_number (amortsched->year_I + 1, 1, 0) - Init_Date_jdn;
d = 366 / PF;
}
else
{
/* Payment frequency per year bi-monthly or less
* use 30 days/month, 360 days/year
*/
if (Eff_Date_jdn == Init_Date_jdn)
{
s = 0;
}
else
{
s =
((amortsched->year_I - amortsched->year_E) * 360) +
((amortsched->month_I - amortsched->month_E) * 30) +
amortsched->day_I - amortsched->day_E;
} /* endif */
days_to_yr_end = 390 - (amortsched->month_I * 30) - amortsched->day_I;
d = 360 / PF;
} /* endif */
if (!bep)
{
/* ordinary annuity
*/
s -= d;
} /* endif */
amortsched->yr_pmt = (days_to_yr_end + d) / d;
if (pmt == 0.0)
{
amortsched->pve = pv;
}
else
{
amortsched->pve =
rnd (pv * pow ((1.0 + eint), ((double) (s * PF) / (double) (d * CF))),
prec);
} /* endif */
pve = amortsched->pve;
/* compute new data to fully amortize loan:
* new periodic payment, new_pmt
*
* option 1: Amortize with original transaction - ignore interest
* due to delayed initial payment
*
* option 2: Amortize with new pv, pve == original pv adjusted for
* delayed initial payment, original payment, original fv and
* original total number of payments, adjust final payment
*
* option 3: amortize with new pv, pve, and new payments adjusted to
* minimize final payment, keep original number of payments and
* original fv
*
* option 4: amortize with new pv, pve, original payments and new
* number of payments to keep original final fv */
/* option 3, compute new periodic payment */
amortsched->new_pmt = new_pmt =
rnd (_fi_calc_payment (n, nint, pve, fv, CF, PF, disc, bep), prec);
/* option 4: compute new number of total payments, new_n */
amortsched->new_n = new_n =
(unsigned)
rnd (_fi_calc_num_payments (nint, pve, pmt, fv, CF, PF, disc, bep), 0);
/* following used in QTAwk to insure integer value, not needed in C */
/* n = int(n); */
/* compute payment for constant payment to principal loan and final
* payment for original loan amount include interest due */
amortsched->cpmt1 = rnd (-pv / n, prec);
amortsched->final_pmt_opt_1 = -pv - amortsched->cpmt1 * (n - 1);
amortsched->final_pmt_opt_1 *= eint + 1;
/* compute payment for constant payment to principal loan and final
* payment for delayed loan amount include interest due */
amortsched->cpmt2 = rnd (-pve / n, prec);
amortsched->final_pmt_opt_2 = -pve - amortsched->cpmt2 * (n - 1);
amortsched->final_pmt_opt_2 *= eint + 1;
if (bep)
{
amortsched->final_pmt_opt_3 =
rnd (_fi_calc_future_value (n - 1, nint, pv, pmt, CF, PF, disc, bep) -
(fv / (1.0 + eint)), prec);
amortsched->final_pmt_opt_4 =
rnd (_fi_calc_future_value (n - 1, nint, pve, pmt, CF, PF, disc, bep) -
(fv / (1.0 + eint)), prec);
amortsched->final_pmt_opt_5 =
rnd (_fi_calc_future_value
(n - 1, nint, pve, new_pmt, CF, PF, disc,
bep) - (fv / (1.0 + eint)), prec);
if (new_n)
amortsched->final_pmt_opt_6 =
rnd (_fi_calc_future_value
(new_n - 1, nint, pve, pmt, CF, PF, disc,
bep) - (fv / (1.0 + eint)), prec);
else
amortsched->final_pmt_opt_6 = 0.0;
}
else
{
amortsched->final_pmt_opt_3 =
rnd (_fi_calc_future_value (n - 1, nint, pv, pmt, CF, PF, disc, bep) *
(1.0 + eint) - fv, prec);
amortsched->final_pmt_opt_4 =
rnd (_fi_calc_future_value (n - 1, nint, pve, pmt, CF, PF, disc, bep) *
(1.0 + eint) - fv, prec);
amortsched->final_pmt_opt_5 =
rnd (_fi_calc_future_value
(n - 1, nint, pve, new_pmt, CF, PF, disc, bep) * (1.0 + eint) - fv,
prec);
if (new_n)
amortsched->final_pmt_opt_6 =
rnd (_fi_calc_future_value
(new_n - 1, nint, pve, pmt, CF, PF, disc,
bep) * (1.0 + eint) - fv, prec);
else
amortsched->final_pmt_opt_6 = 0.0;
} /* endif */
/* compute delayed interest */
amortsched->delayed_int = pv - amortsched->pve;
return amortsched;
} /* Amortization_init */
amort_sched_ptr
Amortization_Schedule (amort_sched_ptr amortsched)
{
unsigned n = amortsched->n;
double nint = amortsched->nint;
double pv = amortsched->pv;
double pmt = amortsched->pmt;
double fv = amortsched->fv;
double eint = amortsched->eint;
unsigned CF = amortsched->CF;
unsigned PF = amortsched->PF;
unsigned disc = amortsched->disc;
unsigned bep = amortsched->bep;
double cpmt = 0;
double final_pmt = 0;
char summary = amortsched->summary;
unsigned option = amortsched->option;
unsigned yr_pmt = amortsched->yr_pmt;
unsigned fv_case = amortsched->fv_case;
unsigned prec = amortsched->prec;
unsigned j, s, yr, per_cnt, pmt_cnt = 0, k = 0, sum_prt;
int jj;
unsigned long d;
double yr_fv, sum_int, yr_int, prin, adv_pmt, pmt_int, hpv = 0.0;
yearly_summary_ptr yrly_sum;
amort_sched_yr_ptr amortyr;
sched_pmt_ptr pmtsched = NULL;
sum_int = yr_int = 0.0;
switch (option)
{
case 1:
amortsched->cpmt = cpmt = amortsched->cpmt1;
/* re-compute final payment without interest
*/
amortsched->final_pmt = final_pmt = -pv - cpmt * (n - 1);
summary = (summary == 'y') ? 'x' : 'o';
break;
case 2:
amortsched->cpmt = cpmt = amortsched->cpmt2;
pv = amortsched->pve;
/* re-compute final payment without interest
*/
amortsched->final_pmt = final_pmt = -pv - cpmt * (n - 1);
summary = (summary == 'y') ? 'x' : 'o';
break;
case 3:
amortsched->final_pmt = final_pmt = amortsched->final_pmt_opt_3;
break;
case 4:
pv = amortsched->pve;
amortsched->final_pmt = final_pmt = amortsched->final_pmt_opt_4;
break;
case 5:
pv = amortsched->pve;
pmt = amortsched->new_pmt;
amortsched->final_pmt = final_pmt = amortsched->final_pmt_opt_5;
break;
case 6:
n = amortsched->new_n;
pv = amortsched->pve;
amortsched->final_pmt = final_pmt = amortsched->final_pmt_opt_6;
break;
} /* endswitch */
yr = amortsched->year_I;
sum_prt = TRUE;
switch (summary)
{
case 'a':
/* variable advanced prepayment schedule. prepayment equals next
* period principal. */
amortsched->schedule.first_yr =
amortyr = (amort_sched_yr_ptr) calloc (1, sizeof (amort_sched_yr));
for (per_cnt = 0, s = 1, j = n; pv != fv; j -= 2, per_cnt++)
{
/* basic equation to compute interest this payment period */
pmt_int = -rnd ((pv + (amortsched->bp * pmt)) * eint, prec);
/* sum yearly interest paid */
yr_int += pmt_int;
/* sum total interest paid */
sum_int += pmt_int;
/* compute principal paid this payment period and round to
nearest cent */
if (dabs (pmt) > dabs (pv))
{
prin = -pv;
pmt = prin + pmt_int;
adv_pmt = 0.0;
pv = fv;
}
else
{
prin = rnd (pmt - pmt_int, prec);
/* compute remaining pv and round to nearest cent */
pv = rnd (pv + prin, prec);
/* compute principal for next payment cycle and round to
nearest cent */
adv_pmt = rnd (pmt + (pv + (amortsched->bp * pmt)) * eint, prec);
if (dabs (pv) >= dabs (adv_pmt))
{
/* remaining pv greater than advanced principal payment
* compute remaining pv and round to nearest cent */
pv = rnd (pv + adv_pmt, prec);
}
else
{
/* remaining pv less than advanced principal payment reduce
* advanced pricipla payment to remaining pv */
adv_pmt = -pv;
/* and set remaining pv to fv */
pv = fv;
} /* ## endif */
} /* # endif */
if (sum_prt)
{
jj = (j < yr_pmt) ? j + 1 : yr_pmt;
amortyr->payments =
pmtsched = (sched_pmt_ptr) calloc (jj, sizeof (sched_pmt));
pmt_cnt = 0;
sum_prt = FALSE;
} /* endif */
pmtsched->period_num = s++;
pmtsched->interest = pmt_int;
pmtsched->principal = prin;
pmtsched->advanced_pmt = adv_pmt;
pmtsched->total_pmt = pmt + adv_pmt;
pmtsched->balance = pv;
pmtsched++;
pmt_cnt++;
if (!--yr_pmt)
{
yr_pmt = PF;
amortyr->year = yr++;
amortyr->interest_pd = yr_int;
amortyr->principal_pd = pv - hpv;
amortyr->yr_end_balance = pv;
amortyr->total_interest_pd = sum_int;
amortyr->num_periods = pmt_cnt;
amortyr->next_yr =
(amort_sched_yr_ptr) calloc (1, sizeof (amort_sched_yr));
amortyr = amortyr->next_yr;
hpv = pv;
yr_int = 0.0;
sum_prt = TRUE;
} /* endif */
} /* endfor */
if (dabs (pv) > 0.0)
{
/* basic equation to compute interest this payment period */
pmt_int = -rnd ((pv + (amortsched->bp * pmt)) * eint, prec);
/* sum yearly interest paid */
yr_int += pmt_int;
/* sum total interest paid */
sum_int += pmt_int;
/* compute principal paid this payment period and round to
nearest cent */
prin = rnd (pmt - pmt_int, prec);
final_pmt = pmt;
/* compute remaining pv and round to nearest cent */
pv = rnd (pv + prin, prec);
/* Set advanced principal payment to remaining pv */
adv_pmt = -pv;
amortyr->final_pmt = final_pmt += adv_pmt;
/* and set remaining pv to fv */
pv = fv;
if (pmtsched)
{
pmtsched->period_num = s++;
pmtsched->interest = pmt_int;
pmtsched->principal = prin;
pmtsched->advanced_pmt = adv_pmt;
pmtsched->total_pmt = final_pmt;
pmtsched->balance = pv;
}
per_cnt++;
pmt_cnt++;
} /* endif */
if (dabs (yr_int) > 0.0)
{
amortyr->year = yr++;
amortyr->interest_pd = yr_int;
amortyr->principal_pd = pv - hpv;
amortyr->total_interest_pd = sum_int;
amortyr->num_periods = pmt_cnt;
} /* endif */
amortsched->total_periods = per_cnt;
break;
case 'f':
/* fixed prepaymet schedule prepayment specified by user */
amortsched->schedule.first_yr =
amortyr = (amort_sched_yr_ptr) calloc (1, sizeof (amort_sched_yr));
/* set advnaced payment */
adv_pmt = amortsched->fixed_pmt;
for (per_cnt = 0, s = 1, j = n; j && (pv != fv); j--, per_cnt++)
{
/* basic equation to compute interest this payment period */
pmt_int = -rnd ((pv + (amortsched->bp * pmt)) * eint, prec);
/* sum yearly interest paid
*/
yr_int += pmt_int;
/* sum total interest paid */
sum_int += pmt_int;
/* compute principal paid this payment period and round to
nearest cent */
if (dabs (pmt) > dabs (pv))
{
prin = -pv;
pmt = prin + pmt_int;
adv_pmt = 0.0;
pv = 0.0;
}
else
{
prin = rnd (pmt - pmt_int, prec);
/* compute remaining pv and round to nearest cent */
pv = rnd (pv + prin, prec);
if (dabs (pv) >= dabs (adv_pmt))
{
/* remaining pv greater than advanced principal payment
* compute remaining pv and round to nearest cent */
pv = rnd (pv + adv_pmt, prec);
}
else
{
/* remaining pv less than advanced principal payment reduce
* advanced pricipal payment to remaining pv and set
* remaining pv to fv */
adv_pmt = -pv;
pv = fv;
} /*## endif */
} /* # endif */
if (sum_prt)
{
jj = (j < yr_pmt) ? j + 1 : yr_pmt;
amortyr->payments =
pmtsched = (sched_pmt_ptr) calloc (jj, sizeof (sched_pmt));
pmt_cnt = 0;
sum_prt = FALSE;
}
else
{
(amortyr->num_periods)++;
} /* ## endif */
pmtsched->period_num = s++;
pmtsched->interest = pmt_int;
pmtsched->principal = prin;
pmtsched->advanced_pmt = adv_pmt;
pmtsched->total_pmt = pmt + adv_pmt;
pmtsched->balance = pv;
pmt_cnt++;
pmtsched++;
if (!--yr_pmt)
{
yr_pmt = PF;
amortyr->year = yr++;
amortyr->interest_pd = yr_int;
amortyr->principal_pd = pv - hpv;
amortyr->yr_end_balance = pv;
amortyr->total_interest_pd = sum_int;
amortyr->num_periods = pmt_cnt;
amortyr->next_yr =
(amort_sched_yr_ptr) calloc (1, sizeof (amort_sched_yr));
amortyr = amortyr->next_yr;
hpv = pv;
yr_int = 0.0;
sum_prt = TRUE;
} /* ## endif */
} /* ## endfor */
if (pv != fv)
{
/* # basic equation to compute interest this payment period */
pmt_int = -rnd ((pv + (amortsched->bp * pmt)) * eint, prec);
/* # sum yearly interest paid */
yr_int += pmt_int;
/* # sum total interest paid */
sum_int += pmt_int;
/* # compute principal paid this payment period and round to
nearest cent */
prin = rnd (pmt - pmt_int, prec);
final_pmt = pmt;
/* # compute remaining pv and round to nearest cent */
pv = rnd (pv + prin, prec);
/* # Set advanced principal payment to remaining pv */
adv_pmt = -pv;
amortyr->final_pmt = final_pmt += adv_pmt;
/* # and set remaining pv to fv */
pv = fv;
if (pmtsched)
{
pmtsched->period_num = s++;
pmtsched->interest = pmt_int;
pmtsched->principal = prin;
pmtsched->advanced_pmt = adv_pmt;
pmtsched->total_pmt = final_pmt;
pmtsched->balance = pv;
}
per_cnt++;
pmt_cnt++;
} /* # endif */
if (dabs (yr_int) > 0.0)
{
amortyr->year = yr++;
amortyr->interest_pd = yr_int;
amortyr->principal_pd = pv - hpv;
amortyr->total_interest_pd = sum_int;
amortyr->num_periods = pmt_cnt;
} /* endif */
amortsched->total_periods = per_cnt;
break;
case 'o':
/* Constant payment to principal use constant payment equal to
* original pv divided by number of periods. constant payment to
* pricipal could be amount specified by user. */
amortsched->schedule.first_yr =
amortyr = (amort_sched_yr_ptr) calloc (1, sizeof (amort_sched_yr));
amortsched->total_periods = n;
d = yr_pmt;
for (s = 1, j = n - 1; j; j--, k++)
{
pmt_int = -rnd (pv * eint, prec);
/* sum yearly interest paid */
yr_int += pmt_int;
/* sum total interest paid */
sum_int += pmt_int;
pv = rnd (pv + cpmt, prec);
if (sum_prt)
{
jj = (j < yr_pmt) ? j + 1 : yr_pmt;
amortyr->payments =
pmtsched = (sched_pmt_ptr) calloc (jj, sizeof (sched_pmt));
amortyr->num_periods = jj;
k = 0;
sum_prt = FALSE;
} /* endif */
pmtsched->period_num = s++;
pmtsched->interest = pmt_int;
pmtsched->total_pmt = cpmt + pmt_int;
pmtsched->balance = pv;
pmtsched++;
if (!--yr_pmt)
{
yr_pmt = PF;
amortyr->year = yr++;
amortyr->interest_pd = yr_int;
amortyr->principal_pd = d * cpmt;
amortyr->yr_end_balance = pv;
amortyr->total_interest_pd = sum_int;
amortyr->next_yr =
(amort_sched_yr_ptr) calloc (1, sizeof (amort_sched_yr));
amortyr = amortyr->next_yr;
d = PF;
yr_int = 0.0;
sum_prt = TRUE;
} /* endif */
} /* endfor */
if (pv)
{
pmt_int = -rnd (pv * eint, prec);
/* sum yearly interest paid */
yr_int += pmt_int;
/* sum total interest paid */
sum_int += pmt_int;
if (pmtsched)
{
pmtsched->period_num = s++;
pmtsched->interest = -pmt_int;
pmtsched->total_pmt = -pv + pmt_int;
pmtsched->balance = 0.0;
}
amortyr->final_pmt = -pv - pmt_int;
} /* endif */
if (dabs (yr_int) > 0.0)
{
amortyr->year = yr++;
amortyr->interest_pd = yr_int;
amortyr->principal_pd = -pv + k * cpmt;
amortyr->total_interest_pd = sum_int;
} /* endif */
break;
case 'p':
/* normal amortization schedule interest, principal and balance
* per payment period */
amortsched->schedule.first_yr =
amortyr = (amort_sched_yr_ptr) calloc (1, sizeof (amort_sched_yr));
amortsched->total_periods = n;
hpv = pv;
for (s = 1, j = n - 1; j; j--)
{
/* basic equation for computing interest paid in payment period */
pmt_int = -rnd ((pv + (amortsched->bp * pmt)) * eint, prec);
/* sum yearly interest paid */
yr_int += pmt_int;
/* sum total interest paid */
sum_int += pmt_int;
/* compute principal paid this payment period */
prin = rnd (pmt - pmt_int, prec);
/* compute remaining pv and round to nearest cent */
pv = rnd (pv + prin, prec);
if (sum_prt)
{
jj = (j < yr_pmt) ? j + 1 : yr_pmt;
amortyr->payments =
pmtsched = (sched_pmt_ptr) calloc (jj, sizeof (sched_pmt));
amortyr->num_periods = jj;
sum_prt = FALSE;
} /* endif */
if (fv_case)
{
pmtsched->period_num = s++;
pmtsched->interest = pmt_int;
pmtsched->balance = pv;
pmtsched++;
}
else
{
pmtsched->period_num = s++;
pmtsched->interest = pmt_int;
pmtsched->principal = prin;
pmtsched->balance = pv;
pmtsched++;
} /* endif */
if (!--yr_pmt)
{
yr_pmt = PF;
amortyr->year = yr++;
amortyr->interest_pd = yr_int;
if (!fv_case)
{
amortyr->principal_pd = pv - hpv;
} /* endif */
amortyr->yr_end_balance = pv;
amortyr->total_interest_pd = sum_int;
amortyr->next_yr =
(amort_sched_yr_ptr) calloc (1, sizeof (amort_sched_yr));
amortyr = amortyr->next_yr;
hpv = pv;
yr_int = 0.0;
sum_prt = TRUE;
} /* * endif */
} /* * endfor */
/* determine if payment due at beginning or end of period in order
* to correctly compute final payment, interest and principal */
if (bep)
{
/* paying remainder at beginning of period compute final payment */
final_pmt = -pv - fv / (1 + eint);
/* then compute interest paid with final final payment */
pmt_int = -rnd ((pv + final_pmt) * eint, prec);
/* then compute the principal paid */
prin = final_pmt + pmt_int;
}
else
{
/* basic equation for computing interest paid in payment period
* for payment at end of period */
pmt_int = -rnd (pv * eint, prec);
/* compute principal paid this payment period */
prin = -pv;
/* compute the final payment note the final payment may be
* computed either of two ways both are equivalent */
final_pmt = prin + pmt_int;
} /* * endif */
pv = -fv;
/* sum yearly interest paid */
yr_int += pmt_int;
/* sum total interest paid */
sum_int += pmt_int;
if (sum_prt)
{
amortyr->payments =
pmtsched = (sched_pmt_ptr) calloc (1, sizeof (sched_pmt));
amortyr->num_periods = 1;
} /* endif */
amortyr->final_pmt = final_pmt;
if (fv_case)
{
pmtsched->period_num = s++;
pmtsched->interest = pmt_int;
pmtsched->balance = pv;
}
else
{
pmtsched->period_num = s++;
pmtsched->interest = pmt_int;
pmtsched->principal = prin;
pmtsched->balance = pv;
} /* endif */
if (dabs (yr_int) > 0.0)
{
amortyr->year = yr++;
amortyr->interest_pd = yr_int;
amortyr->total_interest_pd = sum_int;
if (!bep)
{
amortyr->principal_pd = -hpv;
} /* endif */
} /* endif */
break;
case 'x':
/* constant payment to principal - annual summary */
/* compute number of years to summarize */
j = n / PF;
if (yr_pmt < PF)
j++;
amortsched->total_periods = j;
amortsched->schedule.summary =
yrly_sum = (yearly_summary_ptr) calloc (j, sizeof (yearly_summary));
jj = 0;
for (j = n, sum_prt = 0; j > 0; j -= yr_pmt, yr_pmt = PF, sum_prt++)
{
if (j <= PF)
{
s = jj + j;
yr_pmt = j;
yr_fv = rnd (pv + cpmt * (s - 1), prec) + final_pmt;
}
else
{
s = jj + yr_pmt;
yr_fv = rnd (pv + cpmt * s, prec);
} /* endif */
prin = -eint * jj * (pv + (cpmt * (jj - 1) / 2.0));
yr_int = -eint * s * (pv + (cpmt * (s - 1) / 2.0));
yr_int = rnd (yr_int - prin, prec);
jj += yr_pmt;
sum_int += yr_int;
yrly_sum[sum_prt].year = yr++;
yrly_sum[sum_prt].interest = yr_int;
yrly_sum[sum_prt].end_balance = yr_fv;
} /* endfor */
break;
case 'y':
/* normal amortization - annual summary */
/* compute number of years to summarize */
j = n / PF;
if (yr_pmt < PF)
j++;
if (n > (j * PF))
j++;
amortsched->total_periods = j;
amortsched->schedule.summary =
yrly_sum = (yearly_summary_ptr) calloc (j, sizeof (yearly_summary));
hpv = pv;
for (jj = n, j = 0; jj > 0; jj -= yr_pmt, yr_pmt = PF, j++)
{
if (jj <= (int)PF)
{
yr_fv = fv;
yr_int = rnd (((jj - 1) * pmt) + hpv + final_pmt, prec);
}
else
{
yr_fv =
-rnd (_fi_calc_future_value
(yr_pmt, nint, hpv, pmt, CF, PF, disc, bep), prec);
yr_int = rnd ((yr_pmt * pmt) + hpv - yr_fv, prec);
} /* * endif */
sum_int += yr_int;
yrly_sum[j].year = yr++;
yrly_sum[j].interest = yr_int;
yrly_sum[j].end_balance = yr_fv;
hpv = yr_fv;
} /* * endfor */
break;
} /* * endswitch */
amortsched->total_interest = sum_int;
return amortsched;
} /* Amortization_Schedule */
/* function to free dynamically allocated memory used for amortization
schedule */
void
Amortization_free (amort_sched_ptr amortsched)
{
amort_sched_yr_ptr amortyr, prst_yr;
switch (amortsched->summary)
{
case 'a':
case 'f':
case 'o':
case 'p':
for (amortyr = amortsched->schedule.first_yr; amortyr; amortyr = prst_yr)
{
if (amortyr->payments)
free (amortyr->payments);
prst_yr = amortyr->next_yr;
free (amortyr);
} /* endfor */
break;
case 'y':
free (amortsched->schedule.summary);
break;
} /* endswitch */
amortsched->schedule.first_yr = NULL;
} /* amort_free */