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  */
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)
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
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
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
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
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
224 {
225  return ((a.num == b.num) && (a.denom == b.denom));
226 }
227 
228 /* *******************************************************************
229  * QofNumeric_equal
230  ********************************************************************/
231 
232 gboolean
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 
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))
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
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)
358  ca = mult128 (a.num, lcd / a.denom);
359  if (ca.isbig)
361  cb = mult128 (b.num, lcd / b.denom);
362  if (cb.isbig)
364  cab = add128 (ca, cb);
365  if (cab.isbig)
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 
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))
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 
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))
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
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. */
475  {
476  if (bigdeno.isbig)
478  product = reduce128 (bignume, product.denom);
479  if (qof_numeric_check (product))
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)
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 
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))
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
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  {
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. */
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  {
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 
638 {
639  if (qof_numeric_check (a))
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 
651 {
652  if (qof_numeric_check (a))
654  return qof_numeric_create (ABS (a.num), a.denom);
655 }
656 
657 /* *******************************************************************
658  * qof_numeric_convert
659  ********************************************************************/
660 
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))
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 
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)
699  else
700  return in;
701  break;
702 
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)
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 
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 
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:
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 
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))
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 
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:
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
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
1005 {
1006  return qof_numeric_create (error_code, 0LL);
1007 }
1008 
1009 /* *******************************************************************
1010  * qof_numeric_add_with_error
1011  ********************************************************************/
1012 
1013 QofNumeric
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,
1021  QofNumeric err = qof_numeric_sub (sum, exact, QOF_DENOM_AUTO,
1023 
1024  if (error)
1025  *error = err;
1026  return sum;
1027 }
1028 
1029 /* *******************************************************************
1030  * qof_numeric_sub_with_error
1031  ********************************************************************/
1032 
1033 QofNumeric
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,
1040  QofNumeric err = qof_numeric_sub (diff, exact, QOF_DENOM_AUTO,
1042  if (error)
1043  *error = err;
1044  return diff;
1045 }
1046 
1047 /* *******************************************************************
1048  * qof_numeric_mul_with_error
1049  ********************************************************************/
1050 
1051 QofNumeric
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,
1058  QofNumeric err = qof_numeric_sub (prod, exact, QOF_DENOM_AUTO,
1060  if (error)
1061  *error = err;
1062  return prod;
1063 }
1064 
1065 
1066 /* *******************************************************************
1067  * qof_numeric_div_with_error
1068  ********************************************************************/
1069 
1070 QofNumeric
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,
1077  QofNumeric err = qof_numeric_sub (quot, exact,
1079  if (error)
1080  *error = err;
1081  return quot;
1082 }
1083 
1084 /* ***************************************************************
1085  * QofNumeric text IO
1086  ****************************************************************/
1087 
1088 gchar *
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 *
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
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
1213 
1214 
1215  return 0;
1216 }
1217 #endif
1218 
1219 /* ======================== END OF FILE =================== */