Files
gnucash/libgnucash/app-utils/calculation/fin.c
Geert Janssens 83d14e1c1c Restructure the src directory
It is split into
- /libgnucash (for the non-gui bits)
- /gnucash (for the gui)
- /common (misc source files used by both)
- /bindings (currently only holds python bindings)

This is the first step in restructuring the code. It will need much
more fine tuning later on.
2017-08-10 18:45:00 +02:00

2472 lines
82 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 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)
{
s = 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));
d = pv;
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;
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));
d = pv;
/* 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;
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;
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 */