QOF: qofnumeric.c Source File

QOF 0.7.5

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