QOF  0.8.7
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-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 /* =============================================================== */
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
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
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)
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
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
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
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
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
219 {
220  return ((a.num == b.num) && (a.denom == b.denom));
221 }
222 
223 /* *******************************************************************
224  * QofNumeric_equal
225  ********************************************************************/
226 
227 gboolean
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
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 
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))
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
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)
353  ca = mult128 (a.num, lcd / a.denom);
354  if (ca.isbig)
356  cb = mult128 (b.num, lcd / b.denom);
357  if (cb.isbig)
359  cab = add128 (ca, cb);
360  if (cab.isbig)
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 
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))
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 
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))
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
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. */
470  {
471  if (bigdeno.isbig)
473  product = reduce128 (bignume, product.denom);
474  if (qof_numeric_check (product))
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)
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 
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))
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
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  {
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. */
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  {
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 
633 {
634  if (qof_numeric_check (a))
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 
646 {
647  if (qof_numeric_check (a))
649  return qof_numeric_create (ABS (a.num), a.denom);
650 }
651 
652 /* *******************************************************************
653  * qof_numeric_convert
654  ********************************************************************/
655 
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))
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 
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)
694  else
695  return in;
696  break;
697 
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)
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 
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 
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:
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 
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))
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 
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:
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
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 
1000 {
1001  return qof_numeric_create (error_code, 0LL);
1002 }
1003 
1004 /* *******************************************************************
1005  * qof_numeric_add_with_error
1006  ********************************************************************/
1007 
1008 QofNumeric
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,
1016  QofNumeric err = qof_numeric_sub (sum, exact, QOF_DENOM_AUTO,
1018 
1019  if (error)
1020  *error = err;
1021  return sum;
1022 }
1023 
1024 /* *******************************************************************
1025  * qof_numeric_sub_with_error
1026  ********************************************************************/
1027 
1028 QofNumeric
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,
1035  QofNumeric err = qof_numeric_sub (diff, exact, QOF_DENOM_AUTO,
1037  if (error)
1038  *error = err;
1039  return diff;
1040 }
1041 
1042 /* *******************************************************************
1043  * qof_numeric_mul_with_error
1044  ********************************************************************/
1045 
1046 QofNumeric
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,
1053  QofNumeric err = qof_numeric_sub (prod, exact, QOF_DENOM_AUTO,
1055  if (error)
1056  *error = err;
1057  return prod;
1058 }
1059 
1060 
1061 /* *******************************************************************
1062  * qof_numeric_div_with_error
1063  ********************************************************************/
1064 
1065 QofNumeric
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,
1072  QofNumeric err = qof_numeric_sub (quot, exact,
1074  if (error)
1075  *error = err;
1076  return quot;
1077 }
1078 
1079 /* ***************************************************************
1080  * QofNumeric text IO
1081  ****************************************************************/
1082 
1083 gchar *
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 *
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
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 =================== */
guint64 gcf64(guint64 num, guint64 denom)
Definition: qofmath128.c:278
QofNumericErrorCode qof_numeric_check(QofNumeric in)
Definition: qofnumeric.c:39
QofNumeric qof_numeric_mul_with_error(QofNumeric a, QofNumeric b, gint64 denom, gint how, QofNumeric *error)
Definition: qofnumeric.c:1047
gint qof_numeric_same(QofNumeric a, QofNumeric b, gint64 denom, gint how)
Definition: qofnumeric.c:280
QofNumeric qof_numeric_mul(QofNumeric a, QofNumeric b, gint64 denom, gint how)
Definition: qofnumeric.c:400
gint qof_numeric_compare(QofNumeric a, QofNumeric b)
Definition: qofnumeric.c:169
gshort isneg
Definition: qofmath128.h:42
An exact-rational-number library for QOF.
QofNumeric qof_numeric_sub_with_error(QofNumeric a, QofNumeric b, gint64 denom, gint how, QofNumeric *error)
Definition: qofnumeric.c:1029
gint cmp128(QofInt128 a, QofInt128 b)
Definition: qofmath128.c:246
QofNumeric qof_numeric_error(QofNumericErrorCode error_code)
Definition: qofnumeric.c:999
gint64 rem128(QofInt128 n, gint64 d)
Definition: qofmath128.c:220
gdouble qof_numeric_to_double(QofNumeric in)
Definition: qofnumeric.c:986
gboolean qof_numeric_equal(QofNumeric a, QofNumeric b)
Definition: qofnumeric.c:228
#define QOF_NUMERIC_RND_MASK
bitmasks for HOW flags.
Definition: qofnumeric.h:116
QofNumeric qof_numeric_div_with_error(QofNumeric a, QofNumeric b, gint64 denom, gint how, QofNumeric *error)
Definition: qofnumeric.c:1066
gchar * qof_numeric_dbg_to_string(QofNumeric n)
Definition: qofnumeric.c:1098
QofInt128 shift128(QofInt128 x)
Definition: qofmath128.c:110
QofNumeric qof_numeric_add_with_error(QofNumeric a, QofNumeric b, gint64 denom, gint how, QofNumeric *error)
Definition: qofnumeric.c:1009
QofInt128 div128(QofInt128 n, gint64 d)
Definition: qofmath128.c:180
QofNumeric qof_numeric_abs(QofNumeric a)
Definition: qofnumeric.c:645
gboolean qof_numeric_from_string(const gchar *str, QofNumeric *n)
Definition: qofnumeric.c:1116
QofNumeric qof_numeric_reduce(QofNumeric in)
Definition: qofnumeric.c:883
static QofNumeric qof_numeric_create(gint64 num, gint64 denom)
Definition: qofnumeric.h:243
gboolean qof_numeric_zero_p(QofNumeric a)
Definition: qofnumeric.c:114
gboolean qof_numeric_eq(QofNumeric a, QofNumeric b)
Definition: qofnumeric.c:218
QofInt128 add128(QofInt128 a, QofInt128 b)
Definition: qofmath128.c:308
QofNumeric qof_numeric_neg(QofNumeric a)
Definition: qofnumeric.c:632
QofNumeric qof_numeric_sub(QofNumeric a, QofNumeric b, gint64 denom, gint how)
Definition: qofnumeric.c:383
gchar * qof_numeric_to_string(QofNumeric n)
Definition: qofnumeric.c:1084
QofNumericErrorCode
Definition: qofnumeric.h:207
gboolean qof_numeric_negative_p(QofNumeric a)
Definition: qofnumeric.c:132
gboolean equal128(QofInt128 a, QofInt128 b)
Definition: qofmath128.c:233
QofNumeric qof_numeric_convert(QofNumeric in, gint64 denom, gint how)
Definition: qofnumeric.c:657
QofNumeric qof_numeric_add(QofNumeric a, QofNumeric b, gint64 denom, gint how)
Definition: qofnumeric.c:295
QofNumeric qof_numeric_from_double(gdouble in, gint64 denom, gint how)
Definition: qofnumeric.c:914
gboolean qof_numeric_positive_p(QofNumeric a)
Definition: qofnumeric.c:150
gshort isbig
Definition: qofmath128.h:43
QofNumeric qof_numeric_div(QofNumeric a, QofNumeric b, gint64 denom, gint how)
Definition: qofnumeric.c:511
QofInt128 mult128(gint64 a, gint64 b)
Definition: qofmath128.c:41
#define QOF_DENOM_AUTO
Definition: qofnumeric.h:231
QofInt128 lcm128(guint64 a, guint64 b)
Definition: qofmath128.c:299