1201 #if defined(G_OS_WIN32) && !defined(_MSC_VER) 1209 #include "finproto.h" 1210 #include "fin_static_proto.h" 1215 rnd (
double x,
unsigned places)
1217 static const size_t buflen = 50;
1221 snprintf (buf, buflen,
"%.*f", (
int) places, x);
1222 r = strtod(buf, NULL);
1232 return (x >= 0.0) ? x : -x;
1237 _A (
double eint,
unsigned per)
1239 return pow ((1.0 + eint), (
double) per) - 1.0;
1244 _B (
double eint,
unsigned beg)
1248 g_return_val_if_fail(eint != 0.0, 0.0);
1249 return (1.0 + eint * (
double) beg) / eint;
1254 _C (
double eint,
double pmt,
unsigned beg)
1256 g_return_val_if_fail(eint != 0.0, 0.0);
1257 return pmt * _B(eint, beg);
1262 fi_calc_num_payments (fi_ptr fi)
1266 rnd (_fi_calc_num_payments
1267 (fi->ir, fi->pv, fi->pmt, fi->fv, fi->CF, fi->PF, fi->disc, fi->bep),
1278 _fi_calc_num_payments (
double nint,
1287 double eint = eff_int (nint / 100.0, CF, PF, disc);
1288 double CC = _C (eint, pmt, bep);
1289 CC = (CC - fv) / (CC + pv);
1290 return (CC > 0.0) ? log (CC) / log (1.0 + eint) : 0.0;
1295 fi_calc_interest (fi_ptr fi)
1298 fi->ir = _fi_calc_interest (fi->npp, fi->pv, fi->pmt, fi->fv,
1299 fi->CF, fi->PF, fi->disc, fi->bep);
1313 _fi_calc_interest (
unsigned per,
1327 eint = pow ((dabs (fv) / dabs (pv)), (1.0 / (
double) per)) - 1.0;
1330 if ((pmt * fv) < 0.0)
1337 dabs ((fv + a * (
double) per * pmt) /
1339 (((
double) per - 1.0) * ((
double) per - 1.0) * pmt + pv -
1344 if ((pv * pmt) < 0.0)
1346 eint = dabs (((
double) per * pmt + pv + fv) / ((
double) per * pv));
1350 a = dabs (pmt / (dabs (pv) + dabs (fv)));
1351 eint = a + 1.0 / (a * (double) per * (
double) per * (double) per);
1357 fi (per, eint, pv, pmt, fv, bep) / fip (per, eint, pv, pmt, fv, bep);
1359 (void) modf (ratio * (dik / eint), &a);
1365 return 100.0 * nom_int (eint, CF, PF, disc);
1370 fi_calc_present_value (fi_ptr fi)
1373 rnd (_fi_calc_present_value
1374 (fi->npp, fi->ir, fi->pmt, fi->fv, fi->CF, fi->PF, fi->disc,
1375 fi->bep), fi->prec);
1385 _fi_calc_present_value (
unsigned per,
1394 double eint = eff_int (nint / 100.0, CF, PF, disc);
1395 double AA = _A (eint, per);
1396 double CC = _C (eint, pmt, bep);
1398 return -(fv + (AA * CC)) / (AA + 1.0);
1403 fi_calc_payment (fi_ptr fi)
1406 rnd (_fi_calc_payment
1407 (fi->npp, fi->ir, fi->pv, fi->fv, fi->CF, fi->PF, fi->disc, fi->bep),
1418 _fi_calc_payment (
unsigned per,
1427 double eint = eff_int (nint / 100.0, CF, PF, disc);
1428 double AA = _A (eint, per);
1429 double BB = _B (eint, bep);
1430 g_return_val_if_fail(BB != 0.0, 0.0);
1432 return -(fv + pv * (AA + 1.0)) / (AA * BB);
1437 fi_calc_future_value (fi_ptr fi)
1440 rnd (_fi_calc_future_value
1441 (fi->npp, fi->ir, fi->pv, fi->pmt, fi->CF, fi->PF, fi->disc,
1442 fi->bep), fi->prec);
1452 _fi_calc_future_value (
unsigned per,
1461 double eint = eff_int (nint / 100.0, CF, PF, disc);
1462 double AA = _A (eint, per);
1463 double CC = _C (eint, pmt, bep);
1465 return -(pv + AA * (pv + CC));
1470 nom_int (
double eint,
unsigned CF,
unsigned PF,
unsigned disc)
1482 nint = CF * (pow ((1.0 + eint), ((
double) PF / (
double) CF)) - 1.0);
1486 nint = log (pow (1.0 + eint, PF));
1493 eff_int (
double nint,
unsigned CF,
unsigned PF,
unsigned disc)
1501 eint = nint / (double) CF;
1506 pow ((1.0 + nint / (
double) CF), ((
double) CF / (
double) PF)) - 1.0;
1510 eint = exp (nint / (
double) PF) - 1.0;
1517 fi (
unsigned per,
double eint,
double pv,
double pmt,
double fv,
unsigned bep)
1519 return _A (eint, per) * (pv + _C (eint, pmt, bep)) + pv + fv;
1525 fip (
unsigned per,
double eint,
double pv,
double pmt,
double fv,
unsigned bep)
1527 double AA = _A (eint, per);
1528 double CC = _C (eint, pmt, bep);
1529 double D = (AA + 1.0) / (1.0 + eint);
1530 g_return_val_if_fail(CC != 0.0, 0.0);
1531 return (
double) per * (pv + CC) * D - (AA * CC) / eint;
1535 set_default (fi_ptr fi)
1554 fi->CF = fi->PF = 12;
1582 julian_day_number (
unsigned year,
unsigned month,
unsigned day)
1588 unsigned gregorian = TRUE;
1593 yr = year + (month - 3.0) / 12.0;
1594 ljdn = (long) (367.0 * yr + pfac) - (2 * (long) (yr)) + (
long) (yr / 4.0)
1595 + (long) day + 1721117L;
1597 ljdn += -(long) (yr / 100.0) + (long) (yr / 400.0) + 2;
1603 Amortization_init (amort_sched_ptr amortsched)
1605 unsigned n = amortsched->n;
1606 double nint = amortsched->nint;
1607 double pv = amortsched->pv;
1608 double pmt = amortsched->pmt;
1609 double fv = amortsched->fv;
1613 unsigned CF = amortsched->CF;
1614 unsigned PF = amortsched->PF;
1615 unsigned disc = amortsched->disc;
1616 unsigned bep = amortsched->bep;
1618 unsigned prec = amortsched->prec;
1623 julian_day_number (amortsched->year_E, amortsched->month_E,
1624 amortsched->day_E), Init_Date_jdn =
1625 julian_day_number (amortsched->year_I, amortsched->month_I,
1628 amortsched->Eff_Date_jdn = Eff_Date_jdn;
1629 amortsched->Init_Date_jdn = Init_Date_jdn;
1630 amortsched->yday_E =
1631 Eff_Date_jdn - julian_day_number (amortsched->year_E, 1, 1);
1632 amortsched->yday_I =
1633 Init_Date_jdn - julian_day_number (amortsched->year_I, 1, 1);
1634 amortsched->eint = eint = eff_int (nint / 100.0, CF, PF, disc);
1635 amortsched->fv_case = dabs (fv) > dabs (pv);
1636 amortsched->bp = bep ? 1.0 : 0.0;
1643 s = Init_Date_jdn - Eff_Date_jdn;
1645 julian_day_number (amortsched->year_I + 1, 1, 0) - Init_Date_jdn;
1653 if (Eff_Date_jdn == Init_Date_jdn)
1660 ((amortsched->year_I - amortsched->year_E) * 360) +
1661 ((amortsched->month_I - amortsched->month_E) * 30) +
1662 amortsched->day_I - amortsched->day_E;
1664 days_to_yr_end = 390 - (amortsched->month_I * 30) - amortsched->day_I;
1675 amortsched->yr_pmt = (days_to_yr_end + d) / d;
1679 amortsched->pve = pv;
1684 rnd (pv * pow ((1.0 + eint), ((
double) (s * PF) / (
double) (d * CF))),
1688 pve = amortsched->pve;
1708 amortsched->new_pmt = new_pmt =
1709 rnd (_fi_calc_payment (n, nint, pve, fv, CF, PF, disc, bep), prec);
1712 amortsched->new_n = new_n =
1714 rnd (_fi_calc_num_payments (nint, pve, pmt, fv, CF, PF, disc, bep), 0);
1721 amortsched->cpmt1 = rnd (-pv / n, prec);
1722 amortsched->final_pmt_opt_1 = -pv - amortsched->cpmt1 * (n - 1);
1723 amortsched->final_pmt_opt_1 *= eint + 1;
1727 amortsched->cpmt2 = rnd (-pve / n, prec);
1728 amortsched->final_pmt_opt_2 = -pve - amortsched->cpmt2 * (n - 1);
1729 amortsched->final_pmt_opt_2 *= eint + 1;
1733 amortsched->final_pmt_opt_3 =
1734 rnd (_fi_calc_future_value (n - 1, nint, pv, pmt, CF, PF, disc, bep) -
1735 (fv / (1.0 + eint)), prec);
1736 amortsched->final_pmt_opt_4 =
1737 rnd (_fi_calc_future_value (n - 1, nint, pve, pmt, CF, PF, disc, bep) -
1738 (fv / (1.0 + eint)), prec);
1739 amortsched->final_pmt_opt_5 =
1740 rnd (_fi_calc_future_value
1741 (n - 1, nint, pve, new_pmt, CF, PF, disc,
1742 bep) - (fv / (1.0 + eint)), prec);
1744 amortsched->final_pmt_opt_6 =
1745 rnd (_fi_calc_future_value
1746 (new_n - 1, nint, pve, pmt, CF, PF, disc,
1747 bep) - (fv / (1.0 + eint)), prec);
1749 amortsched->final_pmt_opt_6 = 0.0;
1753 amortsched->final_pmt_opt_3 =
1754 rnd (_fi_calc_future_value (n - 1, nint, pv, pmt, CF, PF, disc, bep) *
1755 (1.0 + eint) - fv, prec);
1756 amortsched->final_pmt_opt_4 =
1757 rnd (_fi_calc_future_value (n - 1, nint, pve, pmt, CF, PF, disc, bep) *
1758 (1.0 + eint) - fv, prec);
1759 amortsched->final_pmt_opt_5 =
1760 rnd (_fi_calc_future_value
1761 (n - 1, nint, pve, new_pmt, CF, PF, disc, bep) * (1.0 + eint) - fv,
1764 amortsched->final_pmt_opt_6 =
1765 rnd (_fi_calc_future_value
1766 (new_n - 1, nint, pve, pmt, CF, PF, disc,
1767 bep) * (1.0 + eint) - fv, prec);
1769 amortsched->final_pmt_opt_6 = 0.0;
1773 amortsched->delayed_int = pv - amortsched->pve;
1779 Amortization_Schedule (amort_sched_ptr amortsched)
1781 unsigned n = amortsched->n;
1782 double nint = amortsched->nint;
1783 double pv = amortsched->pv;
1784 double pmt = amortsched->pmt;
1785 double fv = amortsched->fv;
1786 double eint = amortsched->eint;
1787 unsigned CF = amortsched->CF;
1788 unsigned PF = amortsched->PF;
1789 unsigned disc = amortsched->disc;
1790 unsigned bep = amortsched->bep;
1792 double final_pmt = 0;
1793 char summary = amortsched->summary;
1794 unsigned option = amortsched->option;
1795 unsigned yr_pmt = amortsched->yr_pmt;
1796 unsigned fv_case = amortsched->fv_case;
1797 unsigned prec = amortsched->prec;
1798 unsigned j, s, yr, per_cnt, pmt_cnt = 0, k = 0, sum_prt;
1804 double yr_fv, sum_int, yr_int, prin, adv_pmt, pmt_int, hpv = 0.0;
1805 yearly_summary_ptr yrly_sum;
1806 amort_sched_yr_ptr amortyr;
1807 sched_pmt_ptr pmtsched = NULL;
1809 sum_int = yr_int = 0.0;
1814 amortsched->cpmt = cpmt = amortsched->cpmt1;
1817 amortsched->final_pmt = final_pmt = -pv - cpmt * (n - 1);
1818 summary = (summary ==
'y') ?
'x' :
'o';
1821 amortsched->cpmt = cpmt = amortsched->cpmt2;
1822 pv = amortsched->pve;
1825 amortsched->final_pmt = final_pmt = -pv - cpmt * (n - 1);
1826 summary = (summary ==
'y') ?
'x' :
'o';
1829 amortsched->final_pmt = final_pmt = amortsched->final_pmt_opt_3;
1832 pv = amortsched->pve;
1833 amortsched->final_pmt = final_pmt = amortsched->final_pmt_opt_4;
1836 pv = amortsched->pve;
1837 pmt = amortsched->new_pmt;
1838 amortsched->final_pmt = final_pmt = amortsched->final_pmt_opt_5;
1841 n = amortsched->new_n;
1842 pv = amortsched->pve;
1843 amortsched->final_pmt = final_pmt = amortsched->final_pmt_opt_6;
1847 yr = amortsched->year_I;
1854 amortsched->schedule.first_yr =
1855 amortyr = (amort_sched_yr_ptr) calloc (1,
sizeof (
amort_sched_yr));
1857 for (per_cnt = 0, s = 1, j = n; pv != fv; j -= 2, per_cnt++)
1860 pmt_int = -rnd ((pv + (amortsched->bp * pmt)) * eint, prec);
1870 if (dabs (pmt) > dabs (pv))
1873 pmt = prin + pmt_int;
1879 prin = rnd (pmt - pmt_int, prec);
1882 pv = rnd (pv + prin, prec);
1886 adv_pmt = rnd (pmt + (pv + (amortsched->bp * pmt)) * eint, prec);
1888 if (dabs (pv) >= dabs (adv_pmt))
1892 pv = rnd (pv + adv_pmt, prec);
1907 jj = (j < yr_pmt) ? j + 1 : yr_pmt;
1909 pmtsched = (sched_pmt_ptr) calloc (jj,
sizeof (
sched_pmt));
1915 pmtsched->period_num = s++;
1916 pmtsched->interest = pmt_int;
1917 pmtsched->principal = prin;
1918 pmtsched->advanced_pmt = adv_pmt;
1919 pmtsched->total_pmt = pmt + adv_pmt;
1920 pmtsched->balance = pv;
1928 amortyr->year = yr++;
1929 amortyr->interest_pd = yr_int;
1930 amortyr->principal_pd = pv - hpv;
1931 amortyr->yr_end_balance = pv;
1932 amortyr->total_interest_pd = sum_int;
1933 amortyr->num_periods = pmt_cnt;
1936 amortyr = amortyr->next_yr;
1944 if (dabs (pv) > 0.0)
1947 pmt_int = -rnd ((pv + (amortsched->bp * pmt)) * eint, prec);
1957 prin = rnd (pmt - pmt_int, prec);
1961 pv = rnd (pv + prin, prec);
1965 amortyr->final_pmt = final_pmt += adv_pmt;
1972 pmtsched->period_num = s++;
1973 pmtsched->interest = pmt_int;
1974 pmtsched->principal = prin;
1975 pmtsched->advanced_pmt = adv_pmt;
1976 pmtsched->total_pmt = final_pmt;
1977 pmtsched->balance = pv;
1984 if (dabs (yr_int) > 0.0)
1986 amortyr->year = yr++;
1987 amortyr->interest_pd = yr_int;
1988 amortyr->principal_pd = pv - hpv;
1989 amortyr->total_interest_pd = sum_int;
1990 amortyr->num_periods = pmt_cnt;
1993 amortsched->total_periods = per_cnt;
1997 amortsched->schedule.first_yr =
1998 amortyr = (amort_sched_yr_ptr) calloc (1,
sizeof (
amort_sched_yr));
2001 adv_pmt = amortsched->fixed_pmt;
2003 for (per_cnt = 0, s = 1, j = n; j && (pv != fv); j--, per_cnt++)
2006 pmt_int = -rnd ((pv + (amortsched->bp * pmt)) * eint, prec);
2015 if (dabs (pmt) > dabs (pv))
2018 pmt = prin + pmt_int;
2024 prin = rnd (pmt - pmt_int, prec);
2027 pv = rnd (pv + prin, prec);
2029 if (dabs (pv) >= dabs (adv_pmt))
2033 pv = rnd (pv + adv_pmt, prec);
2047 jj = (j < yr_pmt) ? j + 1 : yr_pmt;
2049 pmtsched = (sched_pmt_ptr) calloc (jj,
sizeof (
sched_pmt));
2056 (amortyr->num_periods)++;
2059 pmtsched->period_num = s++;
2060 pmtsched->interest = pmt_int;
2061 pmtsched->principal = prin;
2062 pmtsched->advanced_pmt = adv_pmt;
2063 pmtsched->total_pmt = pmt + adv_pmt;
2064 pmtsched->balance = pv;
2072 amortyr->year = yr++;
2073 amortyr->interest_pd = yr_int;
2074 amortyr->principal_pd = pv - hpv;
2075 amortyr->yr_end_balance = pv;
2076 amortyr->total_interest_pd = sum_int;
2077 amortyr->num_periods = pmt_cnt;
2080 amortyr = amortyr->next_yr;
2091 pmt_int = -rnd ((pv + (amortsched->bp * pmt)) * eint, prec);
2100 prin = rnd (pmt - pmt_int, prec);
2104 pv = rnd (pv + prin, prec);
2108 amortyr->final_pmt = final_pmt += adv_pmt;
2115 pmtsched->period_num = s++;
2116 pmtsched->interest = pmt_int;
2117 pmtsched->principal = prin;
2118 pmtsched->advanced_pmt = adv_pmt;
2119 pmtsched->total_pmt = final_pmt;
2120 pmtsched->balance = pv;
2127 if (dabs (yr_int) > 0.0)
2129 amortyr->year = yr++;
2130 amortyr->interest_pd = yr_int;
2131 amortyr->principal_pd = pv - hpv;
2132 amortyr->total_interest_pd = sum_int;
2133 amortyr->num_periods = pmt_cnt;
2136 amortsched->total_periods = per_cnt;
2142 amortsched->schedule.first_yr =
2143 amortyr = (amort_sched_yr_ptr) calloc (1,
sizeof (
amort_sched_yr));
2144 amortsched->total_periods = n;
2147 for (s = 1, j = n - 1; j; j--, k++)
2149 pmt_int = -rnd (pv * eint, prec);
2157 pv = rnd (pv + cpmt, prec);
2161 jj = (j < yr_pmt) ? j + 1 : yr_pmt;
2163 pmtsched = (sched_pmt_ptr) calloc (jj,
sizeof (
sched_pmt));
2164 amortyr->num_periods = jj;
2170 pmtsched->period_num = s++;
2171 pmtsched->interest = pmt_int;
2172 pmtsched->total_pmt = cpmt + pmt_int;
2173 pmtsched->balance = pv;
2180 amortyr->year = yr++;
2181 amortyr->interest_pd = yr_int;
2182 amortyr->principal_pd = d * cpmt;
2183 amortyr->yr_end_balance = pv;
2184 amortyr->total_interest_pd = sum_int;
2187 amortyr = amortyr->next_yr;
2197 pmt_int = -rnd (pv * eint, prec);
2206 pmtsched->period_num = s++;
2207 pmtsched->interest = -pmt_int;
2208 pmtsched->total_pmt = -pv + pmt_int;
2209 pmtsched->balance = 0.0;
2212 amortyr->final_pmt = -pv - pmt_int;
2215 if (dabs (yr_int) > 0.0)
2217 amortyr->year = yr++;
2218 amortyr->interest_pd = yr_int;
2219 amortyr->principal_pd = -pv + k * cpmt;
2220 amortyr->total_interest_pd = sum_int;
2226 amortsched->schedule.first_yr =
2227 amortyr = (amort_sched_yr_ptr) calloc (1,
sizeof (
amort_sched_yr));
2228 amortsched->total_periods = n;
2231 for (s = 1, j = n - 1; j; j--)
2234 pmt_int = -rnd ((pv + (amortsched->bp * pmt)) * eint, prec);
2243 prin = rnd (pmt - pmt_int, prec);
2246 pv = rnd (pv + prin, prec);
2250 jj = (j < yr_pmt) ? j + 1 : yr_pmt;
2252 pmtsched = (sched_pmt_ptr) calloc (jj,
sizeof (
sched_pmt));
2253 amortyr->num_periods = jj;
2260 pmtsched->period_num = s++;
2261 pmtsched->interest = pmt_int;
2262 pmtsched->balance = pv;
2267 pmtsched->period_num = s++;
2268 pmtsched->interest = pmt_int;
2269 pmtsched->principal = prin;
2270 pmtsched->balance = pv;
2278 amortyr->year = yr++;
2279 amortyr->interest_pd = yr_int;
2282 amortyr->principal_pd = pv - hpv;
2284 amortyr->yr_end_balance = pv;
2285 amortyr->total_interest_pd = sum_int;
2288 amortyr = amortyr->next_yr;
2301 final_pmt = -pv - fv / (1 + eint);
2304 pmt_int = -rnd ((pv + final_pmt) * eint, prec);
2307 prin = final_pmt + pmt_int;
2313 pmt_int = -rnd (pv * eint, prec);
2320 final_pmt = prin + pmt_int;
2334 pmtsched = (sched_pmt_ptr) calloc (1,
sizeof (
sched_pmt));
2335 amortyr->num_periods = 1;
2338 amortyr->final_pmt = final_pmt;
2342 pmtsched->period_num = s++;
2343 pmtsched->interest = pmt_int;
2344 pmtsched->balance = pv;
2348 pmtsched->period_num = s++;
2349 pmtsched->interest = pmt_int;
2350 pmtsched->principal = prin;
2351 pmtsched->balance = pv;
2354 if (dabs (yr_int) > 0.0)
2356 amortyr->year = yr++;
2357 amortyr->interest_pd = yr_int;
2358 amortyr->total_interest_pd = sum_int;
2361 amortyr->principal_pd = -hpv;
2372 amortsched->total_periods = j;
2373 amortsched->schedule.summary =
2374 yrly_sum = (yearly_summary_ptr) calloc (j,
sizeof (
yearly_summary));
2377 for (j = n, sum_prt = 0; j > 0; j -= yr_pmt, yr_pmt = PF, sum_prt++)
2383 yr_fv = rnd (pv + cpmt * (s - 1), prec) + final_pmt;
2388 yr_fv = rnd (pv + cpmt * s, prec);
2390 prin = -eint * jj * (pv + (cpmt * (jj - 1) / 2.0));
2391 yr_int = -eint * s * (pv + (cpmt * (s - 1) / 2.0));
2392 yr_int = rnd (yr_int - prin, prec);
2397 yrly_sum[sum_prt].year = yr++;
2398 yrly_sum[sum_prt].interest = yr_int;
2399 yrly_sum[sum_prt].end_balance = yr_fv;
2411 amortsched->total_periods = j;
2412 amortsched->schedule.summary =
2413 yrly_sum = (yearly_summary_ptr) calloc (j,
sizeof (
yearly_summary));
2417 for (jj = n, j = 0; jj > 0; jj -= yr_pmt, yr_pmt = PF, j++)
2422 yr_int = rnd (((jj - 1) * pmt) + hpv + final_pmt, prec);
2427 -rnd (_fi_calc_future_value
2428 (yr_pmt, nint, hpv, pmt, CF, PF, disc, bep), prec);
2429 yr_int = rnd ((yr_pmt * pmt) + hpv - yr_fv, prec);
2434 yrly_sum[j].year = yr++;
2435 yrly_sum[j].interest = yr_int;
2436 yrly_sum[j].end_balance = yr_fv;
2443 amortsched->total_interest = sum_int;
2451 Amortization_free (amort_sched_ptr amortsched)
2453 amort_sched_yr_ptr amortyr, prst_yr;
2455 switch (amortsched->summary)
2461 for (amortyr = amortsched->schedule.first_yr; amortyr; amortyr = prst_yr)
2463 if (amortyr->payments)
2464 free (amortyr->payments);
2465 prst_yr = amortyr->next_yr;
2470 free (amortsched->schedule.summary);
2474 amortsched->schedule.first_yr = NULL;