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