Fix 0^n generating error for fractional n
[gcalctool.git] / src / financial.c
blobfa0e33d3ae856fefa0ab2d28c091da4eaea54490
1 /*
2 * Copyright (C) 1987-2008 Sun Microsystems, Inc. All Rights Reserved.
3 * Copyright (C) 2008-2011 Robert Ancell
5 * This program is free software: you can redistribute it and/or modify it under
6 * the terms of the GNU General Public License as published by the Free Software
7 * Foundation, either version 2 of the License, or (at your option) any later
8 * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
9 * license.
12 #include <glib/gi18n.h>
14 #include "financial.h"
15 #include "mp.h"
17 static void
18 calc_ctrm(MathEquation *equation, MPNumber *t, MPNumber *pint, MPNumber *fv, MPNumber *pv)
21 /* Cterm - pint (periodic interest rate).
22 * fv (future value).
23 * pv (present value).
25 * RESULT = log(fv / pv) / log(1 + pint)
27 MPNumber MP1, MP2, MP3, MP4;
29 mp_divide(fv, pv, &MP1);
30 mp_ln(&MP1, &MP2);
31 mp_add_integer(pint, 1, &MP3);
32 mp_ln(&MP3, &MP4);
33 mp_divide(&MP2, &MP4, t);
37 static void
38 calc_ddb(MathEquation *equation, MPNumber *t, MPNumber *cost, MPNumber *life, MPNumber *period)
41 /* Ddb - cost (amount paid for asset).
42 * life (useful life of the asset).
43 * period (time period for depreciation allowance).
45 * bv = 0.0;
46 * for (i = 0; i < life; i++)
47 * {
48 * VAL = ((cost - bv) * 2) / life
49 * bv += VAL
50 * }
51 * RESULT = VAL
55 int i;
56 int len;
57 MPNumber MPbv, MP1, MP2;
59 mp_set_from_integer(0, &MPbv);
60 len = mp_cast_to_int(period);
61 for (i = 0; i < len; i++) {
62 mp_subtract(cost, &MPbv, &MP1);
63 mp_multiply_integer(&MP1, 2, &MP2);
64 mp_divide(&MP2, life, t);
65 mp_set_from_mp(&MPbv, &MP1);
66 mp_add(&MP1, t, &MPbv); /* TODO: why result is MPbv, for next loop? */
69 if (len >= 0) {
70 math_equation_set_status (equation, _("Error: the number of periods must be positive"));
71 mp_set_from_integer(0, t);
76 static void
77 calc_fv(MathEquation *equation, MPNumber *t, MPNumber *pmt, MPNumber *pint, MPNumber *n)
80 /* Fv - pmt (periodic payment).
81 * pint (periodic interest rate).
82 * n (number of periods).
84 * RESULT = pmt * (pow(1 + pint, n) - 1) / pint
87 MPNumber MP1, MP2, MP3, MP4;
89 mp_add_integer(pint, 1, &MP1);
90 mp_xpowy(&MP1, n, &MP2);
91 mp_add_integer(&MP2, -1, &MP3);
92 mp_multiply(pmt, &MP3, &MP4);
93 mp_divide(&MP4, pint, t);
97 static void
98 calc_gpm(MathEquation *equation, MPNumber *t, MPNumber *cost, MPNumber *margin)
101 /* Gpm - cost (cost of sale).
102 * margin (gross profit margin.
104 * RESULT = cost / (1 - margin)
107 MPNumber MP1, MP2;
109 mp_set_from_integer(1, &MP1);
110 mp_subtract(&MP1, margin, &MP2);
111 mp_divide(cost, &MP2, t);
115 static void
116 calc_pmt(MathEquation *equation, MPNumber *t, MPNumber *prin, MPNumber *pint, MPNumber *n)
119 /* Pmt - prin (principal).
120 * pint (periodic interest rate).
121 * n (term).
123 * RESULT = prin * (pint / (1 - pow(pint + 1, -1 * n)))
126 MPNumber MP1, MP2, MP3, MP4;
128 mp_add_integer(pint, 1, &MP1);
129 mp_multiply_integer(n, -1, &MP2);
130 mp_xpowy(&MP1, &MP2, &MP3);
131 mp_multiply_integer(&MP3, -1, &MP4);
132 mp_add_integer(&MP4, 1, &MP1);
133 mp_divide(pint, &MP1, &MP2);
134 mp_multiply(prin, &MP2, t);
138 static void
139 calc_pv(MathEquation *equation, MPNumber *t, MPNumber *pmt, MPNumber *pint, MPNumber *n)
142 /* Pv - pmt (periodic payment).
143 * pint (periodic interest rate).
144 * n (term).
146 * RESULT = pmt * (1 - pow(1 + pint, -1 * n)) / pint
149 MPNumber MP1, MP2, MP3, MP4;
151 mp_add_integer(pint, 1, &MP1);
152 mp_multiply_integer(n, -1, &MP2);
153 mp_xpowy(&MP1, &MP2, &MP3);
154 mp_multiply_integer(&MP3, -1, &MP4);
155 mp_add_integer(&MP4, 1, &MP1);
156 mp_divide(&MP1, pint, &MP2);
157 mp_multiply(pmt, &MP2, t);
161 static void
162 calc_rate(MathEquation *equation, MPNumber *t, MPNumber *fv, MPNumber *pv, MPNumber *n)
165 /* Rate - fv (future value).
166 * pv (present value).
167 * n (term).
169 * RESULT = pow(fv / pv, 1 / n) - 1
172 MPNumber MP1, MP2, MP3, MP4;
174 mp_divide(fv, pv, &MP1);
175 mp_set_from_integer(1, &MP2);
176 mp_divide(&MP2, n, &MP3);
177 mp_xpowy(&MP1, &MP3, &MP4);
178 mp_add_integer(&MP4, -1, t);
182 static void
183 calc_sln(MathEquation *equation, MPNumber *t, MPNumber *cost, MPNumber *salvage, MPNumber *life)
186 /* Sln - cost (cost of the asset).
187 * salvage (salvage value of the asset).
188 * life (useful life of the asset).
190 * RESULT = (cost - salvage) / life
193 MPNumber MP1;
194 mp_subtract(cost, salvage, &MP1);
195 mp_divide(&MP1, life, t);
199 static void
200 calc_syd(MathEquation *equation, MPNumber *t, MPNumber *cost, MPNumber *salvage, MPNumber *life, MPNumber *period)
203 /* Syd - cost (cost of the asset).
204 * salvage (salvage value of the asset).
205 * life (useful life of the asset).
206 * period (period for which depreciation is computed).
208 * RESULT = (cost - salvage) * (life - period + 1) /
209 * (life * (life + 1)) / 2
212 MPNumber MP1, MP2, MP3, MP4;
214 mp_subtract(life, period, &MP2);
215 mp_add_integer(&MP2, 1, &MP3);
216 mp_add_integer(life, 1, &MP2);
217 mp_multiply(life, &MP2, &MP4);
218 mp_set_from_integer(2, &MP2);
219 mp_divide(&MP4, &MP2, &MP1);
220 mp_divide(&MP3, &MP1, &MP2);
221 mp_subtract(cost, salvage, &MP1);
222 mp_multiply(&MP1, &MP2, t);
226 static void
227 calc_term(MathEquation *equation, MPNumber *t, MPNumber *pmt, MPNumber *fv, MPNumber *pint)
230 /* Term - pmt (periodic payment).
231 * fv (future value).
232 * pint (periodic interest rate).
234 * RESULT = log(1 + (fv * pint / pmt)) / log(1 + pint)
237 MPNumber MP1, MP2, MP3, MP4;
239 mp_add_integer(pint, 1, &MP1);
240 mp_ln(&MP1, &MP2);
241 mp_multiply(fv, pint, &MP1);
242 mp_divide(&MP1, pmt, &MP3);
243 mp_add_integer(&MP3, 1, &MP4);
244 mp_ln(&MP4, &MP1);
245 mp_divide(&MP1, &MP2, t);
249 void
250 do_finc_expression(MathEquation *equation, int function, MPNumber *arg1, MPNumber *arg2, MPNumber *arg3, MPNumber *arg4)
252 MPNumber result;
253 switch (function) {
254 case FINC_CTRM_DIALOG:
255 calc_ctrm(equation, &result, arg1, arg2, arg3);
256 break;
257 case FINC_DDB_DIALOG:
258 calc_ddb(equation, &result, arg1, arg2, arg3);
259 break;
260 case FINC_FV_DIALOG:
261 calc_fv(equation, &result, arg1, arg2, arg3);
262 break;
263 case FINC_GPM_DIALOG:
264 calc_gpm(equation, &result, arg1, arg2);
265 break;
266 case FINC_PMT_DIALOG:
267 calc_pmt(equation, &result, arg1, arg2, arg3);
268 break;
269 case FINC_PV_DIALOG:
270 calc_pv(equation, &result, arg1, arg2, arg3);
271 break;
272 case FINC_RATE_DIALOG:
273 calc_rate(equation, &result, arg1, arg2, arg3);
274 break;
275 case FINC_SLN_DIALOG:
276 calc_sln(equation, &result, arg1, arg2, arg3);
277 break;
278 case FINC_SYD_DIALOG:
279 calc_syd(equation, &result, arg1, arg2, arg3, arg4);
280 break;
281 case FINC_TERM_DIALOG:
282 calc_term(equation, &result, arg1, arg2, arg3);
283 break;
285 math_equation_set_number(equation, &result);