1 /********************************************************************
2 * qofnumeric.c -- an exact-number library for accounting use *
3 * Copyright (C) 2000 Bill Gribble *
4 * Copyright (C) 2004 Linas Vepstas <linas@linas.org> *
5 * Copyright (c) 2006-2008 Neil Williams <linux@codehelp.co.uk> *
6 * *
7 * This program is free software; you can redistribute it and/or *
8 * modify it under the terms of the GNU General Public License as *
9 * published by the Free Software Foundation; either version 2 of *
10 * the License, or (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License*
18 * along with this program; if not, contact: *
19 * *
20 * Free Software Foundation Voice: +1-617-542-5942 *
21 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
22 * Boston, MA 02110-1301, USA gnu@gnu.org *
23 * *
24 *******************************************************************/
25
26 #include "config.h"
27
28 #include <glib.h>
29 #include <math.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include "qof.h"
34 #include "qofnumeric.h"
35 #include "qofmath128.c"
36
37 /* =============================================================== */
38 QofNumericErrorCode
qof_numeric_check(QofNumeric in)39 qof_numeric_check (QofNumeric in)
40 {
41 if (in.denom != 0)
42 return QOF_ERROR_OK;
43 else if (in.num)
44 {
45 if ((0 < in.num) || (-4 > in.num))
46 in.num = (gint64) QOF_ERROR_OVERFLOW;
47 return (QofNumericErrorCode) in.num;
48 }
49 else
50 return QOF_ERROR_ARG;
51 }
52
53 /*
54 * Find the least common multiple of the denominators of a and b.
55 */
56
57 static gint64
qof_numeric_lcd(QofNumeric a,QofNumeric b)58 qof_numeric_lcd (QofNumeric a, QofNumeric b)
59 {
60 QofInt128 lcm;
61 if (qof_numeric_check (a) || qof_numeric_check (b))
62 return QOF_ERROR_ARG;
63 if (b.denom == a.denom)
64 return a.denom;
65 /* Special case: smaller divides smoothly into larger */
66 if ((b.denom < a.denom) && ((a.denom % b.denom) == 0))
67 return a.denom;
68 if ((a.denom < b.denom) && ((b.denom % a.denom) == 0))
69 return b.denom;
70 lcm = lcm128 (a.denom, b.denom);
71 if (lcm.isbig)
72 return QOF_ERROR_ARG;
73 return lcm.lo;
74 }
75
76 /* Return the ratio n/d reduced so that there are no common factors. */
77 static QofNumeric
reduce128(QofInt128 n,gint64 d)78 reduce128 (QofInt128 n, gint64 d)
79 {
80 gint64 t;
81 gint64 num;
82 gint64 denom;
83 QofNumeric out;
84 QofInt128 red;
85
86 t = rem128 (n, d);
87 num = d;
88 denom = t;
89
90 /* The strategy is to use Euclid's algorithm */
91 while (denom > 0)
92 {
93 t = num % denom;
94 num = denom;
95 denom = t;
96 }
97 /* num now holds the GCD (Greatest Common Divisor) */
98
99 red = div128 (n, num);
100 if (red.isbig)
101 return qof_numeric_error (QOF_ERROR_OVERFLOW);
102 out.num = red.lo;
103 if (red.isneg)
104 out.num = -out.num;
105 out.denom = d / num;
106 return out;
107 }
108
109 /* *******************************************************************
110 * qof_numeric_zero_p
111 ********************************************************************/
112
113 gboolean
qof_numeric_zero_p(QofNumeric a)114 qof_numeric_zero_p (QofNumeric a)
115 {
116 if (qof_numeric_check (a))
117 return 0;
118 else
119 {
120 if ((a.num == 0) && (a.denom != 0))
121 return 1;
122 else
123 return 0;
124 }
125 }
126
127 /* *******************************************************************
128 * qof_numeric_negative_p
129 ********************************************************************/
130
131 gboolean
qof_numeric_negative_p(QofNumeric a)132 qof_numeric_negative_p (QofNumeric a)
133 {
134 if (qof_numeric_check (a))
135 return 0;
136 else
137 {
138 if ((a.num < 0) && (a.denom != 0))
139 return 1;
140 else
141 return 0;
142 }
143 }
144
145 /* *******************************************************************
146 * qof_numeric_positive_p
147 ********************************************************************/
148
149 gboolean
qof_numeric_positive_p(QofNumeric a)150 qof_numeric_positive_p (QofNumeric a)
151 {
152 if (qof_numeric_check (a))
153 return 0;
154 else
155 {
156 if ((a.num > 0) && (a.denom != 0))
157 return 1;
158 else
159 return 0;
160 }
161 }
162
163 /* *******************************************************************
164 * qof_numeric_compare
165 * returns 1 if a>b, -1 if b>a, 0 if a == b
166 ********************************************************************/
167
168 gint
qof_numeric_compare(QofNumeric a,QofNumeric b)169 qof_numeric_compare (QofNumeric a, QofNumeric b)
170 {
171 gint64 aa, bb;
172 QofInt128 l, r;
173
174 if (qof_numeric_check (a) || qof_numeric_check (b))
175 return 0;
176
177 if (a.denom == b.denom)
178 {
179 if (a.num == b.num)
180 return 0;
181 if (a.num > b.num)
182 return 1;
183 return -1;
184 }
185
186 if ((a.denom > 0) && (b.denom > 0))
187 {
188 /* Avoid overflows using 128-bit intermediate math */
189 l = mult128 (a.num, b.denom);
190 r = mult128 (b.num, a.denom);
191 return cmp128 (l, r);
192 }
193
194 if (a.denom < 0)
195 a.denom *= -1;
196 if (b.denom < 0)
197 b.denom *= -1;
198
199 /* BUG: Possible overflow here.. Also, doesn't properly deal with
200 * reciprocal denominators.
201 */
202 aa = a.num * a.denom;
203 bb = b.num * b.denom;
204
205 if (aa == bb)
206 return 0;
207 if (aa > bb)
208 return 1;
209 return -1;
210 }
211
212
213 /* *******************************************************************
214 * qof_numeric_eq
215 ********************************************************************/
216
217 gboolean
qof_numeric_eq(QofNumeric a,QofNumeric b)218 qof_numeric_eq (QofNumeric a, QofNumeric b)
219 {
220 return ((a.num == b.num) && (a.denom == b.denom));
221 }
222
223 /* *******************************************************************
224 * QofNumeric_equal
225 ********************************************************************/
226
227 gboolean
qof_numeric_equal(QofNumeric a,QofNumeric b)228 qof_numeric_equal (QofNumeric a, QofNumeric b)
229 {
230 QofInt128 l, r;
231
232 if ((a.denom == b.denom) && (a.denom > 0))
233 return (a.num == b.num);
234 if ((a.denom > 0) && (b.denom > 0))
235 {
236 // return (a.num*b.denom == b.num*a.denom);
237 l = mult128 (a.num, b.denom);
238 r = mult128 (b.num, a.denom);
239 return equal128 (l, r);
240
241 #if ALT_WAY_OF_CHECKING_EQUALITY
242 QofNumeric ra = QofNumeric_reduce (a);
243 QofNumeric rb = QofNumeric_reduce (b);
244 if (ra.denom != rb.denom)
245 return 0;
246 if (ra.num != rb.num)
247 return 0;
248 return 1;
249 #endif
250 }
251 if ((a.denom < 0) && (b.denom < 0))
252 {
253 l = mult128 (a.num, -a.denom);
254 r = mult128 (b.num, -b.denom);
255 return equal128 (l, r);
256 }
257 else
258 {
259 /* BUG: One of the numbers has a reciprocal denom, and the other
260 does not. I just don't know to handle this case in any
261 reasonably overflow-proof yet simple way. So, this funtion
262 will simply get it wrong whenever the three multiplies
263 overflow 64-bits. -CAS */
264 if (a.denom < 0)
265 return ((a.num * -a.denom * b.denom) == b.num);
266 else
267 return (a.num == (b.num * a.denom * -b.denom));
268 }
269 return ((a.num * b.denom) == (a.denom * b.num));
270 }
271
272
273 /* *******************************************************************
274 * qof_numeric_same
275 * would a and b be equal() if they were both converted to the same
276 * denominator?
277 ********************************************************************/
278
279 gint
qof_numeric_same(QofNumeric a,QofNumeric b,gint64 denom,gint how)280 qof_numeric_same (QofNumeric a, QofNumeric b, gint64 denom, gint how)
281 {
282 QofNumeric aconv, bconv;
283
284 aconv = qof_numeric_convert (a, denom, how);
285 bconv = qof_numeric_convert (b, denom, how);
286
287 return (qof_numeric_equal (aconv, bconv));
288 }
289
290 /* *******************************************************************
291 * qof_numeric_add
292 ********************************************************************/
293
294 QofNumeric
qof_numeric_add(QofNumeric a,QofNumeric b,gint64 denom,gint how)295 qof_numeric_add (QofNumeric a, QofNumeric b, gint64 denom, gint how)
296 {
297 QofNumeric sum;
298
299 if (qof_numeric_check (a) || qof_numeric_check (b))
300 return qof_numeric_error (QOF_ERROR_ARG);
301
302 if ((denom == QOF_DENOM_AUTO) &&
303 (how & QOF_NUMERIC_DENOM_MASK) == QOF_HOW_DENOM_FIXED)
304 {
305 if (a.denom == b.denom)
306 denom = a.denom;
307 else if (b.num == 0)
308 {
309 denom = a.denom;
310 b.denom = a.denom;
311 }
312 else if (a.num == 0)
313 {
314 denom = b.denom;
315 a.denom = b.denom;
316 }
317 else
318 return qof_numeric_error (QOF_ERROR_DENOM_DIFF);
319 }
320
321 if (a.denom < 0)
322 {
323 a.num *= -a.denom; /* BUG: overflow not handled. */
324 a.denom = 1;
325 }
326
327 if (b.denom < 0)
328 {
329 b.num *= -b.denom; /* BUG: overflow not handled. */
330 b.denom = 1;
331 }
332
333 /* Get an exact answer.. same denominator is the common case. */
334 if (a.denom == b.denom)
335 {
336 sum.num = a.num + b.num; /* BUG: overflow not handled. */
337 sum.denom = a.denom;
338 }
339 else
340 {
341 /* We want to do this:
342 * sum.num = a.num*b.denom + b.num*a.denom;
343 * sum.denom = a.denom*b.denom;
344 * but the multiply could overflow.
345 * Computing the LCD minimizes likelihood of overflow
346 */
347 gint64 lcd;
348 QofInt128 ca, cb, cab;
349
350 lcd = qof_numeric_lcd (a, b);
351 if (QOF_ERROR_ARG == lcd)
352 return qof_numeric_error (QOF_ERROR_OVERFLOW);
353 ca = mult128 (a.num, lcd / a.denom);
354 if (ca.isbig)
355 return qof_numeric_error (QOF_ERROR_OVERFLOW);
356 cb = mult128 (b.num, lcd / b.denom);
357 if (cb.isbig)
358 return qof_numeric_error (QOF_ERROR_OVERFLOW);
359 cab = add128 (ca, cb);
360 if (cab.isbig)
361 return qof_numeric_error (QOF_ERROR_OVERFLOW);
362 sum.num = cab.lo;
363 if (cab.isneg)
364 sum.num = -sum.num;
365 sum.denom = lcd;
366 }
367
368 if ((denom == QOF_DENOM_AUTO) &&
369 ((how & QOF_NUMERIC_DENOM_MASK) == QOF_HOW_DENOM_LCD))
370 {
371 denom = qof_numeric_lcd (a, b);
372 how = how & QOF_NUMERIC_RND_MASK;
373 }
374
375 return qof_numeric_convert (sum, denom, how);
376 }
377
378 /* ***************************************************************
379 * qof_numeric_sub
380 *****************************************************************/
381
382 QofNumeric
qof_numeric_sub(QofNumeric a,QofNumeric b,gint64 denom,gint how)383 qof_numeric_sub (QofNumeric a, QofNumeric b, gint64 denom, gint how)
384 {
385 QofNumeric nb;
386
387 if (qof_numeric_check (a) || qof_numeric_check (b))
388 return qof_numeric_error (QOF_ERROR_ARG);
389
390 nb = b;
391 nb.num = -nb.num;
392 return qof_numeric_add (a, nb, denom, how);
393 }
394
395 /* ***************************************************************
396 * qof_numeric_mul
397 *****************************************************************/
398
399 QofNumeric
qof_numeric_mul(QofNumeric a,QofNumeric b,gint64 denom,gint how)400 qof_numeric_mul (QofNumeric a, QofNumeric b, gint64 denom, gint how)
401 {
402 QofNumeric product, result;
403 QofInt128 bignume, bigdeno;
404
405 if (qof_numeric_check (a) || qof_numeric_check (b))
406 return qof_numeric_error (QOF_ERROR_ARG);
407
408 if ((denom == QOF_DENOM_AUTO) &&
409 (how & QOF_NUMERIC_DENOM_MASK) == QOF_HOW_DENOM_FIXED)
410 {
411 if (a.denom == b.denom)
412 denom = a.denom;
413 else if (b.num == 0)
414 denom = a.denom;
415 else if (a.num == 0)
416 denom = b.denom;
417 else
418 return qof_numeric_error (QOF_ERROR_DENOM_DIFF);
419 }
420
421 if ((denom == QOF_DENOM_AUTO) &&
422 ((how & QOF_NUMERIC_DENOM_MASK) == QOF_HOW_DENOM_LCD))
423 {
424 denom = qof_numeric_lcd (a, b);
425 how = how & QOF_NUMERIC_RND_MASK;
426 }
427
428 if (a.denom < 0)
429 {
430 a.num *= -a.denom; /* BUG: overflow not handled. */
431 a.denom = 1;
432 }
433
434 if (b.denom < 0)
435 {
436 b.num *= -b.denom; /* BUG: overflow not handled. */
437 b.denom = 1;
438 }
439
440 bignume = mult128 (a.num, b.num);
441 bigdeno = mult128 (a.denom, b.denom);
442 product.num = a.num * b.num;
443 product.denom = a.denom * b.denom;
444
445 /* If it looks to be overflowing, try to reduce the fraction ... */
446 if (bignume.isbig || bigdeno.isbig)
447 {
448 gint64 tmp;
449
450 a = qof_numeric_reduce (a);
451 b = qof_numeric_reduce (b);
452 tmp = a.num;
453 a.num = b.num;
454 b.num = tmp;
455 a = qof_numeric_reduce (a);
456 b = qof_numeric_reduce (b);
457 bignume = mult128 (a.num, b.num);
458 bigdeno = mult128 (a.denom, b.denom);
459 product.num = a.num * b.num;
460 product.denom = a.denom * b.denom;
461 }
462
463 /* If it its still overflowing, and rounding is allowed then round */
464 if (bignume.isbig || bigdeno.isbig)
465 {
466 /* If rounding allowed, then shift until there's no
467 * more overflow. The conversion at the end will fix
468 * things up for the final value. Else overflow. */
469 if ((how & QOF_NUMERIC_RND_MASK) == QOF_HOW_RND_NEVER)
470 {
471 if (bigdeno.isbig)
472 return qof_numeric_error (QOF_ERROR_OVERFLOW);
473 product = reduce128 (bignume, product.denom);
474 if (qof_numeric_check (product))
475 return qof_numeric_error (QOF_ERROR_OVERFLOW);
476 }
477 else
478 {
479 while (bignume.isbig || bigdeno.isbig)
480 {
481 bignume = shift128 (bignume);
482 bigdeno = shift128 (bigdeno);
483 }
484 product.num = bignume.lo;
485 if (bignume.isneg)
486 product.num = -product.num;
487
488 product.denom = bigdeno.lo;
489 if (0 == product.denom)
490 return qof_numeric_error (QOF_ERROR_OVERFLOW);
491 }
492 }
493
494 #if 0 /* currently, product denom won't ever be zero */
495 if (product.denom < 0)
496 {
497 product.num = -product.num;
498 product.denom = -product.denom;
499 }
500 #endif
501
502 result = qof_numeric_convert (product, denom, how);
503 return result;
504 }
505
506 /* *******************************************************************
507 * qof_numeric_div
508 ********************************************************************/
509
510 QofNumeric
qof_numeric_div(QofNumeric a,QofNumeric b,gint64 denom,gint how)511 qof_numeric_div (QofNumeric a, QofNumeric b, gint64 denom, gint how)
512 {
513 QofNumeric quotient;
514 QofInt128 nume, deno;
515
516 if (qof_numeric_check (a) || qof_numeric_check (b))
517 return qof_numeric_error (QOF_ERROR_ARG);
518
519 if ((denom == QOF_DENOM_AUTO) &&
520 (how & QOF_NUMERIC_DENOM_MASK) == QOF_HOW_DENOM_FIXED)
521 {
522 if (a.denom == b.denom)
523 denom = a.denom;
524 else if (a.denom == 0)
525 denom = b.denom;
526 else
527 return qof_numeric_error (QOF_ERROR_DENOM_DIFF);
528 }
529
530 if (a.denom < 0)
531 {
532 a.num *= -a.denom; /* BUG: overflow not handled. */
533 a.denom = 1;
534 }
535
536 if (b.denom < 0)
537 {
538 b.num *= -b.denom; /* BUG: overflow not handled. */
539 b.denom = 1;
540 }
541
542 if (a.denom == b.denom)
543 {
544 quotient.num = a.num;
545 quotient.denom = b.num;
546 }
547 else
548 {
549 gint64 sgn = 1;
550 if (0 > a.num)
551 {
552 sgn = -sgn;
553 a.num = -a.num;
554 }
555 if (0 > b.num)
556 {
557 sgn = -sgn;
558 b.num = -b.num;
559 }
560 nume = mult128 (a.num, b.denom);
561 deno = mult128 (b.num, a.denom);
562
563 /* Try to avoid overflow by removing common factors */
564 if (nume.isbig && deno.isbig)
565 {
566 QofNumeric ra = qof_numeric_reduce (a);
567 QofNumeric rb = qof_numeric_reduce (b);
568 gint64 gcf_nume = gcf64 (ra.num, rb.num);
569 gint64 gcf_deno = gcf64 (rb.denom, ra.denom);
570
571 nume = mult128 (ra.num / gcf_nume, rb.denom / gcf_deno);
572 deno = mult128 (rb.num / gcf_nume, ra.denom / gcf_deno);
573 }
574
575 if ((0 == nume.isbig) && (0 == deno.isbig))
576 {
577 quotient.num = sgn * nume.lo;
578 quotient.denom = deno.lo;
579 goto dive_done;
580 }
581 else if (0 == deno.isbig)
582 {
583 quotient = reduce128 (nume, deno.lo);
584 if (0 == qof_numeric_check (quotient))
585 {
586 quotient.num *= sgn;
587 goto dive_done;
588 }
589 }
590
591 /* If rounding allowed, then shift until there's no
592 * more overflow. The conversion at the end will fix
593 * things up for the final value. */
594 if ((how & QOF_NUMERIC_RND_MASK) == QOF_HOW_RND_NEVER)
595 return qof_numeric_error (QOF_ERROR_OVERFLOW);
596 while (nume.isbig || deno.isbig)
597 {
598 nume = shift128 (nume);
599 deno = shift128 (deno);
600 }
601 quotient.num = sgn * nume.lo;
602 quotient.denom = deno.lo;
603 if (0 == quotient.denom)
604 {
605 return qof_numeric_error (QOF_ERROR_OVERFLOW);
606 }
607 }
608
609 if (quotient.denom < 0)
610 {
611 quotient.num = -quotient.num;
612 quotient.denom = -quotient.denom;
613 }
614
615 dive_done:
616 if ((denom == QOF_DENOM_AUTO) &&
617 ((how & QOF_NUMERIC_DENOM_MASK) == QOF_HOW_DENOM_LCD))
618 {
619 denom = qof_numeric_lcd (a, b);
620 how = how & QOF_NUMERIC_RND_MASK;
621 }
622
623 return qof_numeric_convert (quotient, denom, how);
624 }
625
626 /* *******************************************************************
627 * qof_numeric_neg
628 * negate the argument
629 ********************************************************************/
630
631 QofNumeric
qof_numeric_neg(QofNumeric a)632 qof_numeric_neg (QofNumeric a)
633 {
634 if (qof_numeric_check (a))
635 return qof_numeric_error (QOF_ERROR_ARG);
636 return qof_numeric_create (-a.num, a.denom);
637 }
638
639 /* *******************************************************************
640 * qof_numeric_neg
641 * return the absolute value of the argument
642 ********************************************************************/
643
644 QofNumeric
qof_numeric_abs(QofNumeric a)645 qof_numeric_abs (QofNumeric a)
646 {
647 if (qof_numeric_check (a))
648 return qof_numeric_error (QOF_ERROR_ARG);
649 return qof_numeric_create (ABS (a.num), a.denom);
650 }
651
652 /* *******************************************************************
653 * qof_numeric_convert
654 ********************************************************************/
655
656 QofNumeric
qof_numeric_convert(QofNumeric in,gint64 denom,gint how)657 qof_numeric_convert (QofNumeric in, gint64 denom, gint how)
658 {
659 QofNumeric out;
660 QofNumeric temp;
661 gint64 temp_bc;
662 gint64 temp_a;
663 gint64 remainder;
664 gint64 sign;
665 gint denom_neg = 0;
666 gdouble ratio, logratio;
667 gdouble sigfigs;
668 QofInt128 nume, newm;
669
670 temp.num = 0;
671 temp.denom = 0;
672
673 if (qof_numeric_check (in))
674 return qof_numeric_error (QOF_ERROR_ARG);
675
676 if (denom == QOF_DENOM_AUTO)
677 {
678 switch (how & QOF_NUMERIC_DENOM_MASK)
679 {
680 default:
681 case QOF_HOW_DENOM_LCD: /* LCD is meaningless with AUTO in here */
682 case QOF_HOW_DENOM_EXACT:
683 return in;
684 break;
685
686 case QOF_HOW_DENOM_REDUCE:
687 /* reduce the input to a relatively-prime fraction */
688 return qof_numeric_reduce (in);
689 break;
690
691 case QOF_HOW_DENOM_FIXED:
692 if (in.denom != denom)
693 return qof_numeric_error (QOF_ERROR_DENOM_DIFF);
694 else
695 return in;
696 break;
697
698 case QOF_HOW_DENOM_SIGFIG:
699 ratio = fabs (qof_numeric_to_double (in));
700 if (ratio < 10e-20)
701 logratio = 0;
702 else
703 {
704 logratio = log10 (ratio);
705 logratio = ((logratio > 0.0) ?
706 (floor (logratio) + 1.0) : (ceil (logratio)));
707 }
708 sigfigs = QOF_HOW_GET_SIGFIGS (how);
709
710 if (sigfigs - logratio >= 0)
711 denom = (gint64) (pow (10, sigfigs - logratio));
712 else
713 denom = -((gint64) (pow (10, logratio - sigfigs)));
714
715 how = how & ~QOF_HOW_DENOM_SIGFIG & ~QOF_NUMERIC_SIGFIGS_MASK;
716 break;
717 }
718 }
719
720 /* Make sure we need to do the work */
721 if (in.denom == denom)
722 return in;
723 if (in.num == 0)
724 {
725 out.num = 0;
726 out.denom = denom;
727 return out;
728 }
729
730 /* If the denominator of the input value is negative, get rid of that. */
731 if (in.denom < 0)
732 {
733 in.num = in.num * (-in.denom); /* BUG: overflow not handled. */
734 in.denom = 1;
735 }
736
737 sign = (in.num < 0) ? -1 : 1;
738
739 /* If the denominator is less than zero, we are to interpret it as
740 * the reciprocal of its magnitude. */
741 if (denom < 0)
742 {
743
744 /* XXX FIXME: use 128-bit math here ... */
745 denom = -denom;
746 denom_neg = 1;
747 temp_a = (in.num < 0) ? -in.num : in.num;
748 temp_bc = in.denom * denom; /* BUG: overflow not handled. */
749 remainder = temp_a % temp_bc;
750 out.num = temp_a / temp_bc;
751 out.denom = -denom;
752 }
753 else
754 {
755 /* Do all the modulo and int division on positive values to make
756 * things a little clearer. Reduce the fraction denom/in.denom to
757 * help with range errors */
758 temp.num = denom;
759 temp.denom = in.denom;
760 temp = qof_numeric_reduce (temp);
761
762 /* Symbolically, do the following:
763 * out.num = in.num * temp.num;
764 * remainder = out.num % temp.denom;
765 * out.num = out.num / temp.denom;
766 * out.denom = denom;
767 */
768 nume = mult128 (in.num, temp.num);
769 newm = div128 (nume, temp.denom);
770 remainder = rem128 (nume, temp.denom);
771
772 if (newm.isbig)
773 return qof_numeric_error (QOF_ERROR_OVERFLOW);
774
775 out.num = newm.lo;
776 out.denom = denom;
777 }
778
779 if (remainder)
780 {
781 switch (how & QOF_NUMERIC_RND_MASK)
782 {
783 case QOF_HOW_RND_FLOOR:
784 if (sign < 0)
785 out.num = out.num + 1;
786 break;
787
788 case QOF_HOW_RND_CEIL:
789 if (sign > 0)
790 out.num = out.num + 1;
791 break;
792
793 case QOF_HOW_RND_TRUNC:
794 break;
795
796 case QOF_HOW_RND_PROMOTE:
797 out.num = out.num + 1;
798 break;
799
800 case QOF_HOW_RND_ROUND_HALF_DOWN:
801 if (denom_neg)
802 {
803 if ((2 * remainder) > in.denom * denom)
804 out.num = out.num + 1;
805 }
806 else if ((2 * remainder) > temp.denom)
807 out.num = out.num + 1;
808 /* check that 2*remainder didn't over-flow */
809 else if (((2 * remainder) < remainder) &&
810 (remainder > (temp.denom / 2)))
811 out.num = out.num + 1;
812 break;
813
814 case QOF_HOW_RND_ROUND_HALF_UP:
815 if (denom_neg)
816 {
817 if ((2 * remainder) >= in.denom * denom)
818 out.num = out.num + 1;
819 }
820 else if ((2 * remainder) >= temp.denom)
821 out.num = out.num + 1;
822 /* check that 2*remainder didn't over-flow */
823 else if (((2 * remainder) < remainder) &&
824 (remainder >= (temp.denom / 2)))
825 out.num = out.num + 1;
826 break;
827
828 case QOF_HOW_RND_ROUND:
829 if (denom_neg)
830 {
831 if ((2 * remainder) > in.denom * denom)
832 out.num = out.num + 1;
833 else if ((2 * remainder) == in.denom * denom)
834 {
835 if (out.num % 2)
836 out.num = out.num + 1;
837 }
838 }
839 else
840 {
841 if ((2 * remainder) > temp.denom)
842 out.num = out.num + 1;
843 /* check that 2*remainder didn't over-flow */
844 else if (((2 * remainder) < remainder) &&
845 (remainder > (temp.denom / 2)))
846 {
847 out.num = out.num + 1;
848 }
849 else if ((2 * remainder) == temp.denom)
850 {
851 if (out.num % 2)
852 out.num = out.num + 1;
853 }
854 /* check that 2*remainder didn't over-flow */
855 else if (((2 * remainder) < remainder) &&
856 (remainder == (temp.denom / 2)))
857 {
858 if (out.num % 2)
859 out.num = out.num + 1;
860 }
861 }
862 break;
863
864 case QOF_HOW_RND_NEVER:
865 return qof_numeric_error (QOF_ERROR_REMAINDER);
866 break;
867 }
868 }
869
870 out.num = (sign > 0) ? out.num : (-out.num);
871
872 return out;
873 }
874
875 /* *************************************************************
876 reduce a fraction by GCF elimination. This is NOT done as a
877 part of the arithmetic API unless QOF_HOW_DENOM_REDUCE is
878 specified
879 as the output denominator.
880 ****************************************************************/
881
882 QofNumeric
qof_numeric_reduce(QofNumeric in)883 qof_numeric_reduce (QofNumeric in)
884 {
885 gint64 t;
886 gint64 num = (in.num < 0) ? (-in.num) : in.num;
887 gint64 denom = in.denom;
888 QofNumeric out;
889
890 if (qof_numeric_check (in))
891 return qof_numeric_error (QOF_ERROR_ARG);
892
893 /* The strategy is to use Euclid's algorithm */
894 while (denom > 0)
895 {
896 t = num % denom;
897 num = denom;
898 denom = t;
899 }
900 /* num now holds the GCD (Greatest Common Divisor) */
901
902 /* All calculations are done on positive num, since it's not
903 * well defined what % does for negative values */
904 out.num = in.num / num;
905 out.denom = in.denom / num;
906 return out;
907 }
908
909 /* ***************************************************************
910 * double_to_QofNumeric
911 ****************************************************************/
912
913 QofNumeric
qof_numeric_from_double(gdouble in,gint64 denom,gint how)914 qof_numeric_from_double (gdouble in, gint64 denom, gint how)
915 {
916 QofNumeric out;
917 gint64 int_part = 0;
918 gdouble frac_part;
919 gint64 frac_int = 0;
920 gdouble logval;
921 gdouble sigfigs;
922
923 if ((denom == QOF_DENOM_AUTO) && (how & QOF_HOW_DENOM_SIGFIG))
924 {
925 if (fabs (in) < 10e-20)
926 logval = 0;
927 else
928 {
929 logval = log10 (fabs (in));
930 logval = ((logval > 0.0) ?
931 (floor (logval) + 1.0) : (ceil (logval)));
932 }
933 sigfigs = QOF_HOW_GET_SIGFIGS (how);
934 if (sigfigs - logval >= 0)
935 denom = (gint64) (pow (10, sigfigs - logval));
936 else
937 denom = -((gint64) (pow (10, logval - sigfigs)));
938
939 how = how & ~QOF_HOW_DENOM_SIGFIG & ~QOF_NUMERIC_SIGFIGS_MASK;
940 }
941
942 int_part = (gint64) (floor (fabs (in)));
943 frac_part = in - (double) int_part;
944
945 int_part = int_part * denom;
946 frac_part = frac_part * (double) denom;
947
948 switch (how & QOF_NUMERIC_RND_MASK)
949 {
950 case QOF_HOW_RND_FLOOR:
951 frac_int = (gint64) floor (frac_part);
952 break;
953
954 case QOF_HOW_RND_CEIL:
955 frac_int = (gint64) ceil (frac_part);
956 break;
957
958 case QOF_HOW_RND_TRUNC:
959 frac_int = (gint64) frac_part;
960 break;
961
962 case QOF_HOW_RND_ROUND:
963 case QOF_HOW_RND_ROUND_HALF_UP:
964 frac_int = (gint64) rint (frac_part);
965 break;
966
967 case QOF_HOW_RND_NEVER:
968 frac_int = (gint64) floor (frac_part);
969 if (frac_part != (double) frac_int)
970 {
971 /* signal an error */
972 }
973 break;
974 }
975
976 out.num = int_part + frac_int;
977 out.denom = denom;
978 return out;
979 }
980
981 /* *******************************************************************
982 * qof_numeric_to_double
983 ********************************************************************/
984
985 gdouble
qof_numeric_to_double(QofNumeric in)986 qof_numeric_to_double (QofNumeric in)
987 {
988 if (in.denom > 0)
989 return (gdouble) in.num / (gdouble) in.denom;
990 else
991 return (gdouble) (in.num * -in.denom);
992 }
993
994 /* *******************************************************************
995 * qof_numeric_error
996 ********************************************************************/
997
998 QofNumeric
qof_numeric_error(QofNumericErrorCode error_code)999 qof_numeric_error (QofNumericErrorCode error_code)
1000 {
1001 return qof_numeric_create (error_code, 0LL);
1002 }
1003
1004 /* *******************************************************************
1005 * qof_numeric_add_with_error
1006 ********************************************************************/
1007
1008 QofNumeric
qof_numeric_add_with_error(QofNumeric a,QofNumeric b,gint64 denom,gint how,QofNumeric * error)1009 qof_numeric_add_with_error (QofNumeric a, QofNumeric b,
1010 gint64 denom, gint how, QofNumeric * error)
1011 {
1012
1013 QofNumeric sum = qof_numeric_add (a, b, denom, how);
1014 QofNumeric exact = qof_numeric_add (a, b, QOF_DENOM_AUTO,
1015 QOF_HOW_DENOM_REDUCE);
1016 QofNumeric err = qof_numeric_sub (sum, exact, QOF_DENOM_AUTO,
1017 QOF_HOW_DENOM_REDUCE);
1018
1019 if (error)
1020 *error = err;
1021 return sum;
1022 }
1023
1024 /* *******************************************************************
1025 * qof_numeric_sub_with_error
1026 ********************************************************************/
1027
1028 QofNumeric
qof_numeric_sub_with_error(QofNumeric a,QofNumeric b,gint64 denom,gint how,QofNumeric * error)1029 qof_numeric_sub_with_error (QofNumeric a, QofNumeric b,
1030 gint64 denom, gint how, QofNumeric * error)
1031 {
1032 QofNumeric diff = qof_numeric_sub (a, b, denom, how);
1033 QofNumeric exact = qof_numeric_sub (a, b, QOF_DENOM_AUTO,
1034 QOF_HOW_DENOM_REDUCE);
1035 QofNumeric err = qof_numeric_sub (diff, exact, QOF_DENOM_AUTO,
1036 QOF_HOW_DENOM_REDUCE);
1037 if (error)
1038 *error = err;
1039 return diff;
1040 }
1041
1042 /* *******************************************************************
1043 * qof_numeric_mul_with_error
1044 ********************************************************************/
1045
1046 QofNumeric
qof_numeric_mul_with_error(QofNumeric a,QofNumeric b,gint64 denom,gint how,QofNumeric * error)1047 qof_numeric_mul_with_error (QofNumeric a, QofNumeric b,
1048 gint64 denom, gint how, QofNumeric * error)
1049 {
1050 QofNumeric prod = qof_numeric_mul (a, b, denom, how);
1051 QofNumeric exact = qof_numeric_mul (a, b, QOF_DENOM_AUTO,
1052 QOF_HOW_DENOM_REDUCE);
1053 QofNumeric err = qof_numeric_sub (prod, exact, QOF_DENOM_AUTO,
1054 QOF_HOW_DENOM_REDUCE);
1055 if (error)
1056 *error = err;
1057 return prod;
1058 }
1059
1060
1061 /* *******************************************************************
1062 * qof_numeric_div_with_error
1063 ********************************************************************/
1064
1065 QofNumeric
qof_numeric_div_with_error(QofNumeric a,QofNumeric b,gint64 denom,gint how,QofNumeric * error)1066 qof_numeric_div_with_error (QofNumeric a, QofNumeric b,
1067 gint64 denom, gint how, QofNumeric * error)
1068 {
1069 QofNumeric quot = qof_numeric_div (a, b, denom, how);
1070 QofNumeric exact = qof_numeric_div (a, b, QOF_DENOM_AUTO,
1071 QOF_HOW_DENOM_REDUCE);
1072 QofNumeric err = qof_numeric_sub (quot, exact,
1073 QOF_DENOM_AUTO, QOF_HOW_DENOM_REDUCE);
1074 if (error)
1075 *error = err;
1076 return quot;
1077 }
1078
1079 /* ***************************************************************
1080 * QofNumeric text IO
1081 ****************************************************************/
1082
1083 gchar *
qof_numeric_to_string(QofNumeric n)1084 qof_numeric_to_string (QofNumeric n)
1085 {
1086 gchar *result;
1087 gint64 tmpnum = n.num;
1088 gint64 tmpdenom = n.denom;
1089
1090 result =
1091 g_strdup_printf ("%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, tmpnum,
1092 tmpdenom);
1093
1094 return result;
1095 }
1096
1097 gchar *
qof_numeric_dbg_to_string(QofNumeric n)1098 qof_numeric_dbg_to_string (QofNumeric n)
1099 {
1100 static gchar buff[1000];
1101 static gchar *p = buff;
1102 gint64 tmpnum = n.num;
1103 gint64 tmpdenom = n.denom;
1104
1105 p += 100;
1106 if (p - buff >= 1000)
1107 p = buff;
1108
1109 sprintf (p, "%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, tmpnum,
1110 tmpdenom);
1111
1112 return p;
1113 }
1114
1115 gboolean
qof_numeric_from_string(const gchar * str,QofNumeric * n)1116 qof_numeric_from_string (const gchar * str, QofNumeric * n)
1117 {
1118 size_t G_GNUC_UNUSED num_read;
1119 gint64 tmpnum;
1120 gint64 tmpdenom;
1121
1122 if (!str)
1123 return FALSE;
1124 tmpnum = strtoll (str, NULL, 0);
1125 str = strchr (str, '/');
1126 if (!str)
1127 return FALSE;
1128 str++;
1129 tmpdenom = strtoll (str, NULL, 0);
1130 num_read = strspn (str, "0123456789");
1131 n->num = tmpnum;
1132 n->denom = tmpdenom;
1133 return TRUE;
1134 }
1135
1136 /* ======================== END OF FILE =================== */
1137