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