1 /*
2 * Copyright (C) 1987-2008 Sun Microsystems, Inc. All Rights Reserved.
3 * Copyright (C) 2008-2011 Robert Ancell
4 *
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.
10 */
11
12 #include <glib/gi18n.h>
13
14 #include "financial.h"
15 #include "mp.h"
16
17 static void
calc_ctrm(MPNumber * t,MPNumber * pint,MPNumber * fv,MPNumber * pv)18 calc_ctrm(MPNumber *t, MPNumber *pint, MPNumber *fv, MPNumber *pv)
19 {
20
21 /* Cterm - pint (periodic interest rate).
22 * fv (future value).
23 * pv (present value).
24 *
25 * RESULT = log(fv / pv) / log(1 + pint)
26 */
27 MPNumber MP1 = mp_new();
28 MPNumber MP2 = mp_new();
29 MPNumber MP3 = mp_new();
30 MPNumber MP4 = mp_new();
31
32 mp_divide(fv, pv, &MP1);
33 mp_ln(&MP1, &MP2);
34 mp_add_integer(pint, 1, &MP3);
35 mp_ln(&MP3, &MP4);
36 mp_divide(&MP2, &MP4, t);
37
38 mp_clear(&MP1);
39 mp_clear(&MP2);
40 mp_clear(&MP3);
41 mp_clear(&MP4);
42 }
43
44
45 static void
calc_ddb(MathEquation * equation,MPNumber * t,MPNumber * cost,MPNumber * life,MPNumber * period)46 calc_ddb(MathEquation *equation, MPNumber *t, MPNumber *cost, MPNumber *life, MPNumber *period)
47 {
48
49 /* Ddb - cost (amount paid for asset).
50 * life (useful life of the asset).
51 * period (time period for depreciation allowance).
52 *
53 * bv = 0.0;
54 * for (i = 0; i < life; i++)
55 * {
56 * VAL = ((cost - bv) * 2) / life
57 * bv += VAL
58 * }
59 * RESULT = VAL
60 *
61 */
62
63 long len;
64 MPNumber MPbv = mp_new();
65 MPNumber MP1 = mp_new();
66 MPNumber MP2 = mp_new();
67
68 mp_set_from_integer(0, &MPbv);
69 len = mp_to_integer(period);
70 for (long i = 0; i < len; i++) {
71 mp_subtract(cost, &MPbv, &MP1);
72 mp_multiply_integer(&MP1, 2, &MP2);
73 mp_divide(&MP2, life, t);
74 mp_set_from_mp(&MPbv, &MP1);
75 mp_add(&MP1, t, &MPbv); /* TODO: why result is MPbv, for next loop? */
76 }
77
78 if (len >= 0) {
79 math_equation_set_status (equation, _("Error: the number of periods must be positive"));
80 mp_set_from_integer(0, t);
81 }
82
83 mp_clear(&MPbv);
84 mp_clear(&MP1);
85 mp_clear(&MP2);
86 }
87
88
89 static void
calc_fv(MPNumber * t,MPNumber * pmt,MPNumber * pint,MPNumber * n)90 calc_fv(MPNumber *t, MPNumber *pmt, MPNumber *pint, MPNumber *n)
91 {
92
93 /* Fv - pmt (periodic payment).
94 * pint (periodic interest rate).
95 * n (number of periods).
96 *
97 * RESULT = pmt * (pow(1 + pint, n) - 1) / pint
98 */
99
100 MPNumber MP1 = mp_new();
101 MPNumber MP2 = mp_new();
102 MPNumber MP3 = mp_new();
103 MPNumber MP4 = mp_new();
104
105 mp_add_integer(pint, 1, &MP1);
106 mp_xpowy(&MP1, n, &MP2);
107 mp_add_integer(&MP2, -1, &MP3);
108 mp_multiply(pmt, &MP3, &MP4);
109 mp_divide(&MP4, pint, t);
110
111 mp_clear(&MP1);
112 mp_clear(&MP2);
113 mp_clear(&MP3);
114 mp_clear(&MP4);
115 }
116
117
118 static void
calc_gpm(MPNumber * t,MPNumber * cost,MPNumber * margin)119 calc_gpm(MPNumber *t, MPNumber *cost, MPNumber *margin)
120 {
121
122 /* Gpm - cost (cost of sale).
123 * margin (gross profit margin.
124 *
125 * RESULT = cost / (1 - margin)
126 */
127
128 MPNumber MP1 = mp_new();
129 MPNumber MP2 = mp_new();
130
131 mp_set_from_integer(1, &MP1);
132 mp_subtract(&MP1, margin, &MP2);
133 mp_divide(cost, &MP2, t);
134
135 mp_clear(&MP1);
136 mp_clear(&MP2);
137 }
138
139
140 static void
calc_pmt(MPNumber * t,MPNumber * prin,MPNumber * pint,MPNumber * n)141 calc_pmt(MPNumber *t, MPNumber *prin, MPNumber *pint, MPNumber *n)
142 {
143
144 /* Pmt - prin (principal).
145 * pint (periodic interest rate).
146 * n (term).
147 *
148 * RESULT = prin * (pint / (1 - pow(pint + 1, -1 * n)))
149 */
150
151 MPNumber MP1 = mp_new();
152 MPNumber MP2 = mp_new();
153 MPNumber MP3 = mp_new();
154 MPNumber MP4 = mp_new();
155
156 mp_add_integer(pint, 1, &MP1);
157 mp_multiply_integer(n, -1, &MP2);
158 mp_xpowy(&MP1, &MP2, &MP3);
159 mp_multiply_integer(&MP3, -1, &MP4);
160 mp_add_integer(&MP4, 1, &MP1);
161 mp_divide(pint, &MP1, &MP2);
162 mp_multiply(prin, &MP2, t);
163
164 mp_clear(&MP1);
165 mp_clear(&MP2);
166 mp_clear(&MP3);
167 mp_clear(&MP4);
168 }
169
170
171 static void
calc_pv(MPNumber * t,MPNumber * pmt,MPNumber * pint,MPNumber * n)172 calc_pv(MPNumber *t, MPNumber *pmt, MPNumber *pint, MPNumber *n)
173 {
174
175 /* Pv - pmt (periodic payment).
176 * pint (periodic interest rate).
177 * n (term).
178 *
179 * RESULT = pmt * (1 - pow(1 + pint, -1 * n)) / pint
180 */
181
182 MPNumber MP1 = mp_new();
183 MPNumber MP2 = mp_new();
184 MPNumber MP3 = mp_new();
185 MPNumber MP4 = mp_new();
186
187 mp_add_integer(pint, 1, &MP1);
188 mp_multiply_integer(n, -1, &MP2);
189 mp_xpowy(&MP1, &MP2, &MP3);
190 mp_multiply_integer(&MP3, -1, &MP4);
191 mp_add_integer(&MP4, 1, &MP1);
192 mp_divide(&MP1, pint, &MP2);
193 mp_multiply(pmt, &MP2, t);
194
195 mp_clear(&MP1);
196 mp_clear(&MP2);
197 mp_clear(&MP3);
198 mp_clear(&MP4);
199 }
200
201
202 static void
calc_rate(MPNumber * t,MPNumber * fv,MPNumber * pv,MPNumber * n)203 calc_rate(MPNumber *t, MPNumber *fv, MPNumber *pv, MPNumber *n)
204 {
205
206 /* Rate - fv (future value).
207 * pv (present value).
208 * n (term).
209 *
210 * RESULT = pow(fv / pv, 1 / n) - 1
211 */
212
213 MPNumber MP1 = mp_new();
214 MPNumber MP2 = mp_new();
215 MPNumber MP3 = mp_new();
216 MPNumber MP4 = mp_new();
217
218 mp_divide(fv, pv, &MP1);
219 mp_set_from_integer(1, &MP2);
220 mp_divide(&MP2, n, &MP3);
221 mp_xpowy(&MP1, &MP3, &MP4);
222 mp_add_integer(&MP4, -1, t);
223
224 mp_clear(&MP1);
225 mp_clear(&MP2);
226 mp_clear(&MP3);
227 mp_clear(&MP4);
228 }
229
230
231 static void
calc_sln(MPNumber * t,MPNumber * cost,MPNumber * salvage,MPNumber * life)232 calc_sln(MPNumber *t, MPNumber *cost, MPNumber *salvage, MPNumber *life)
233 {
234
235 /* Sln - cost (cost of the asset).
236 * salvage (salvage value of the asset).
237 * life (useful life of the asset).
238 *
239 * RESULT = (cost - salvage) / life
240 */
241
242 MPNumber MP1 = mp_new();
243 mp_subtract(cost, salvage, &MP1);
244 mp_divide(&MP1, life, t);
245 mp_clear(&MP1);
246 }
247
248
249 static void
calc_syd(MPNumber * t,MPNumber * cost,MPNumber * salvage,MPNumber * life,MPNumber * period)250 calc_syd(MPNumber *t, MPNumber *cost, MPNumber *salvage, MPNumber *life, MPNumber *period)
251 {
252
253 /* Syd - cost (cost of the asset).
254 * salvage (salvage value of the asset).
255 * life (useful life of the asset).
256 * period (period for which depreciation is computed).
257 *
258 * RESULT = (cost - salvage) * (life - period + 1) /
259 * (life * (life + 1)) / 2
260 */
261
262 MPNumber MP1 = mp_new();
263 MPNumber MP2 = mp_new();
264 MPNumber MP3 = mp_new();
265 MPNumber MP4 = mp_new();
266
267 mp_subtract(life, period, &MP2);
268 mp_add_integer(&MP2, 1, &MP3);
269 mp_add_integer(life, 1, &MP2);
270 mp_multiply(life, &MP2, &MP4);
271 mp_set_from_integer(2, &MP2);
272 mp_divide(&MP4, &MP2, &MP1);
273 mp_divide(&MP3, &MP1, &MP2);
274 mp_subtract(cost, salvage, &MP1);
275 mp_multiply(&MP1, &MP2, t);
276
277 mp_clear(&MP1);
278 mp_clear(&MP2);
279 mp_clear(&MP3);
280 mp_clear(&MP4);
281 }
282
283
284 static void
calc_term(MPNumber * t,MPNumber * pmt,MPNumber * fv,MPNumber * pint)285 calc_term(MPNumber *t, MPNumber *pmt, MPNumber *fv, MPNumber *pint)
286 {
287
288 /* Term - pmt (periodic payment).
289 * fv (future value).
290 * pint (periodic interest rate).
291 *
292 * RESULT = log(1 + (fv * pint / pmt)) / log(1 + pint)
293 */
294
295 MPNumber MP1 = mp_new();
296 MPNumber MP2 = mp_new();
297 MPNumber MP3 = mp_new();
298 MPNumber MP4 = mp_new();
299
300 mp_add_integer(pint, 1, &MP1);
301 mp_ln(&MP1, &MP2);
302 mp_multiply(fv, pint, &MP1);
303 mp_divide(&MP1, pmt, &MP3);
304 mp_add_integer(&MP3, 1, &MP4);
305 mp_ln(&MP4, &MP1);
306 mp_divide(&MP1, &MP2, t);
307
308 mp_clear(&MP1);
309 mp_clear(&MP2);
310 mp_clear(&MP3);
311 mp_clear(&MP4);
312 }
313
314
315 void
do_finc_expression(MathEquation * equation,int function,MPNumber * arg1,MPNumber * arg2,MPNumber * arg3,MPNumber * arg4)316 do_finc_expression(MathEquation *equation, int function, MPNumber *arg1, MPNumber *arg2, MPNumber *arg3, MPNumber *arg4)
317 {
318 MPNumber result = mp_new();
319 switch (function) {
320 case FINC_CTRM_DIALOG:
321 calc_ctrm(&result, arg1, arg2, arg3);
322 break;
323 case FINC_DDB_DIALOG:
324 calc_ddb(equation, &result, arg1, arg2, arg3);
325 break;
326 case FINC_FV_DIALOG:
327 calc_fv(&result, arg1, arg2, arg3);
328 break;
329 case FINC_GPM_DIALOG:
330 calc_gpm(&result, arg1, arg2);
331 break;
332 case FINC_PMT_DIALOG:
333 calc_pmt(&result, arg1, arg2, arg3);
334 break;
335 case FINC_PV_DIALOG:
336 calc_pv(&result, arg1, arg2, arg3);
337 break;
338 case FINC_RATE_DIALOG:
339 calc_rate(&result, arg1, arg2, arg3);
340 break;
341 case FINC_SLN_DIALOG:
342 calc_sln(&result, arg1, arg2, arg3);
343 break;
344 case FINC_SYD_DIALOG:
345 calc_syd(&result, arg1, arg2, arg3, arg4);
346 break;
347 case FINC_TERM_DIALOG:
348 calc_term(&result, arg1, arg2, arg3);
349 break;
350 }
351 math_equation_set_number(equation, &result);
352 mp_clear(&result);
353 }
354