QOF
0.8.7
|
00001 /******************************************************************** 00002 * qofnumeric.c -- an exact-number library for accounting use * 00003 * Copyright (C) 2000 Bill Gribble * 00004 * Copyright (C) 2004 Linas Vepstas <linas@linas.org> * 00005 * Copyright (c) 2006-2008 Neil Williams <linux@codehelp.co.uk> * 00006 * * 00007 * This program is free software; you can redistribute it and/or * 00008 * modify it under the terms of the GNU General Public License as * 00009 * published by the Free Software Foundation; either version 2 of * 00010 * the License, or (at your option) any later version. * 00011 * * 00012 * This program is distributed in the hope that it will be useful, * 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00015 * GNU General Public License for more details. * 00016 * * 00017 * You should have received a copy of the GNU General Public License* 00018 * along with this program; if not, contact: * 00019 * * 00020 * Free Software Foundation Voice: +1-617-542-5942 * 00021 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 * 00022 * Boston, MA 02110-1301, USA gnu@gnu.org * 00023 * * 00024 *******************************************************************/ 00025 00026 #include "config.h" 00027 00028 #include <glib.h> 00029 #include <math.h> 00030 #include <stdio.h> 00031 #include <stdlib.h> 00032 #include <string.h> 00033 #include "qof.h" 00034 #include "qofnumeric.h" 00035 #include "qofmath128.c" 00036 00037 /* =============================================================== */ 00038 QofNumericErrorCode 00039 qof_numeric_check (QofNumeric in) 00040 { 00041 if (in.denom != 0) 00042 return QOF_ERROR_OK; 00043 else if (in.num) 00044 { 00045 if ((0 < in.num) || (-4 > in.num)) 00046 in.num = (gint64) QOF_ERROR_OVERFLOW; 00047 return (QofNumericErrorCode) in.num; 00048 } 00049 else 00050 return QOF_ERROR_ARG; 00051 } 00052 00053 /* 00054 * Find the least common multiple of the denominators of a and b. 00055 */ 00056 00057 static gint64 00058 qof_numeric_lcd (QofNumeric a, QofNumeric b) 00059 { 00060 QofInt128 lcm; 00061 if (qof_numeric_check (a) || qof_numeric_check (b)) 00062 return QOF_ERROR_ARG; 00063 if (b.denom == a.denom) 00064 return a.denom; 00065 /* Special case: smaller divides smoothly into larger */ 00066 if ((b.denom < a.denom) && ((a.denom % b.denom) == 0)) 00067 return a.denom; 00068 if ((a.denom < b.denom) && ((b.denom % a.denom) == 0)) 00069 return b.denom; 00070 lcm = lcm128 (a.denom, b.denom); 00071 if (lcm.isbig) 00072 return QOF_ERROR_ARG; 00073 return lcm.lo; 00074 } 00075 00076 /* Return the ratio n/d reduced so that there are no common factors. */ 00077 static QofNumeric 00078 reduce128 (QofInt128 n, gint64 d) 00079 { 00080 gint64 t; 00081 gint64 num; 00082 gint64 denom; 00083 QofNumeric out; 00084 QofInt128 red; 00085 00086 t = rem128 (n, d); 00087 num = d; 00088 denom = t; 00089 00090 /* The strategy is to use Euclid's algorithm */ 00091 while (denom > 0) 00092 { 00093 t = num % denom; 00094 num = denom; 00095 denom = t; 00096 } 00097 /* num now holds the GCD (Greatest Common Divisor) */ 00098 00099 red = div128 (n, num); 00100 if (red.isbig) 00101 return qof_numeric_error (QOF_ERROR_OVERFLOW); 00102 out.num = red.lo; 00103 if (red.isneg) 00104 out.num = -out.num; 00105 out.denom = d / num; 00106 return out; 00107 } 00108 00109 /* ******************************************************************* 00110 * qof_numeric_zero_p 00111 ********************************************************************/ 00112 00113 gboolean 00114 qof_numeric_zero_p (QofNumeric a) 00115 { 00116 if (qof_numeric_check (a)) 00117 return 0; 00118 else 00119 { 00120 if ((a.num == 0) && (a.denom != 0)) 00121 return 1; 00122 else 00123 return 0; 00124 } 00125 } 00126 00127 /* ******************************************************************* 00128 * qof_numeric_negative_p 00129 ********************************************************************/ 00130 00131 gboolean 00132 qof_numeric_negative_p (QofNumeric a) 00133 { 00134 if (qof_numeric_check (a)) 00135 return 0; 00136 else 00137 { 00138 if ((a.num < 0) && (a.denom != 0)) 00139 return 1; 00140 else 00141 return 0; 00142 } 00143 } 00144 00145 /* ******************************************************************* 00146 * qof_numeric_positive_p 00147 ********************************************************************/ 00148 00149 gboolean 00150 qof_numeric_positive_p (QofNumeric a) 00151 { 00152 if (qof_numeric_check (a)) 00153 return 0; 00154 else 00155 { 00156 if ((a.num > 0) && (a.denom != 0)) 00157 return 1; 00158 else 00159 return 0; 00160 } 00161 } 00162 00163 /* ******************************************************************* 00164 * qof_numeric_compare 00165 * returns 1 if a>b, -1 if b>a, 0 if a == b 00166 ********************************************************************/ 00167 00168 gint 00169 qof_numeric_compare (QofNumeric a, QofNumeric b) 00170 { 00171 gint64 aa, bb; 00172 QofInt128 l, r; 00173 00174 if (qof_numeric_check (a) || qof_numeric_check (b)) 00175 return 0; 00176 00177 if (a.denom == b.denom) 00178 { 00179 if (a.num == b.num) 00180 return 0; 00181 if (a.num > b.num) 00182 return 1; 00183 return -1; 00184 } 00185 00186 if ((a.denom > 0) && (b.denom > 0)) 00187 { 00188 /* Avoid overflows using 128-bit intermediate math */ 00189 l = mult128 (a.num, b.denom); 00190 r = mult128 (b.num, a.denom); 00191 return cmp128 (l, r); 00192 } 00193 00194 if (a.denom < 0) 00195 a.denom *= -1; 00196 if (b.denom < 0) 00197 b.denom *= -1; 00198 00199 /* BUG: Possible overflow here.. Also, doesn't properly deal with 00200 * reciprocal denominators. 00201 */ 00202 aa = a.num * a.denom; 00203 bb = b.num * b.denom; 00204 00205 if (aa == bb) 00206 return 0; 00207 if (aa > bb) 00208 return 1; 00209 return -1; 00210 } 00211 00212 00213 /* ******************************************************************* 00214 * qof_numeric_eq 00215 ********************************************************************/ 00216 00217 gboolean 00218 qof_numeric_eq (QofNumeric a, QofNumeric b) 00219 { 00220 return ((a.num == b.num) && (a.denom == b.denom)); 00221 } 00222 00223 /* ******************************************************************* 00224 * QofNumeric_equal 00225 ********************************************************************/ 00226 00227 gboolean 00228 qof_numeric_equal (QofNumeric a, QofNumeric b) 00229 { 00230 QofInt128 l, r; 00231 00232 if ((a.denom == b.denom) && (a.denom > 0)) 00233 return (a.num == b.num); 00234 if ((a.denom > 0) && (b.denom > 0)) 00235 { 00236 // return (a.num*b.denom == b.num*a.denom); 00237 l = mult128 (a.num, b.denom); 00238 r = mult128 (b.num, a.denom); 00239 return equal128 (l, r); 00240 00241 #if ALT_WAY_OF_CHECKING_EQUALITY 00242 QofNumeric ra = QofNumeric_reduce (a); 00243 QofNumeric rb = QofNumeric_reduce (b); 00244 if (ra.denom != rb.denom) 00245 return 0; 00246 if (ra.num != rb.num) 00247 return 0; 00248 return 1; 00249 #endif 00250 } 00251 if ((a.denom < 0) && (b.denom < 0)) 00252 { 00253 l = mult128 (a.num, -a.denom); 00254 r = mult128 (b.num, -b.denom); 00255 return equal128 (l, r); 00256 } 00257 else 00258 { 00259 /* BUG: One of the numbers has a reciprocal denom, and the other 00260 does not. I just don't know to handle this case in any 00261 reasonably overflow-proof yet simple way. So, this funtion 00262 will simply get it wrong whenever the three multiplies 00263 overflow 64-bits. -CAS */ 00264 if (a.denom < 0) 00265 return ((a.num * -a.denom * b.denom) == b.num); 00266 else 00267 return (a.num == (b.num * a.denom * -b.denom)); 00268 } 00269 return ((a.num * b.denom) == (a.denom * b.num)); 00270 } 00271 00272 00273 /* ******************************************************************* 00274 * qof_numeric_same 00275 * would a and b be equal() if they were both converted to the same 00276 * denominator? 00277 ********************************************************************/ 00278 00279 gint 00280 qof_numeric_same (QofNumeric a, QofNumeric b, gint64 denom, gint how) 00281 { 00282 QofNumeric aconv, bconv; 00283 00284 aconv = qof_numeric_convert (a, denom, how); 00285 bconv = qof_numeric_convert (b, denom, how); 00286 00287 return (qof_numeric_equal (aconv, bconv)); 00288 } 00289 00290 /* ******************************************************************* 00291 * qof_numeric_add 00292 ********************************************************************/ 00293 00294 QofNumeric 00295 qof_numeric_add (QofNumeric a, QofNumeric b, gint64 denom, gint how) 00296 { 00297 QofNumeric sum; 00298 00299 if (qof_numeric_check (a) || qof_numeric_check (b)) 00300 return qof_numeric_error (QOF_ERROR_ARG); 00301 00302 if ((denom == QOF_DENOM_AUTO) && 00303 (how & QOF_NUMERIC_DENOM_MASK) == QOF_HOW_DENOM_FIXED) 00304 { 00305 if (a.denom == b.denom) 00306 denom = a.denom; 00307 else if (b.num == 0) 00308 { 00309 denom = a.denom; 00310 b.denom = a.denom; 00311 } 00312 else if (a.num == 0) 00313 { 00314 denom = b.denom; 00315 a.denom = b.denom; 00316 } 00317 else 00318 return qof_numeric_error (QOF_ERROR_DENOM_DIFF); 00319 } 00320 00321 if (a.denom < 0) 00322 { 00323 a.num *= -a.denom; /* BUG: overflow not handled. */ 00324 a.denom = 1; 00325 } 00326 00327 if (b.denom < 0) 00328 { 00329 b.num *= -b.denom; /* BUG: overflow not handled. */ 00330 b.denom = 1; 00331 } 00332 00333 /* Get an exact answer.. same denominator is the common case. */ 00334 if (a.denom == b.denom) 00335 { 00336 sum.num = a.num + b.num; /* BUG: overflow not handled. */ 00337 sum.denom = a.denom; 00338 } 00339 else 00340 { 00341 /* We want to do this: 00342 * sum.num = a.num*b.denom + b.num*a.denom; 00343 * sum.denom = a.denom*b.denom; 00344 * but the multiply could overflow. 00345 * Computing the LCD minimizes likelihood of overflow 00346 */ 00347 gint64 lcd; 00348 QofInt128 ca, cb, cab; 00349 00350 lcd = qof_numeric_lcd (a, b); 00351 if (QOF_ERROR_ARG == lcd) 00352 return qof_numeric_error (QOF_ERROR_OVERFLOW); 00353 ca = mult128 (a.num, lcd / a.denom); 00354 if (ca.isbig) 00355 return qof_numeric_error (QOF_ERROR_OVERFLOW); 00356 cb = mult128 (b.num, lcd / b.denom); 00357 if (cb.isbig) 00358 return qof_numeric_error (QOF_ERROR_OVERFLOW); 00359 cab = add128 (ca, cb); 00360 if (cab.isbig) 00361 return qof_numeric_error (QOF_ERROR_OVERFLOW); 00362 sum.num = cab.lo; 00363 if (cab.isneg) 00364 sum.num = -sum.num; 00365 sum.denom = lcd; 00366 } 00367 00368 if ((denom == QOF_DENOM_AUTO) && 00369 ((how & QOF_NUMERIC_DENOM_MASK) == QOF_HOW_DENOM_LCD)) 00370 { 00371 denom = qof_numeric_lcd (a, b); 00372 how = how & QOF_NUMERIC_RND_MASK; 00373 } 00374 00375 return qof_numeric_convert (sum, denom, how); 00376 } 00377 00378 /* *************************************************************** 00379 * qof_numeric_sub 00380 *****************************************************************/ 00381 00382 QofNumeric 00383 qof_numeric_sub (QofNumeric a, QofNumeric b, gint64 denom, gint how) 00384 { 00385 QofNumeric nb; 00386 00387 if (qof_numeric_check (a) || qof_numeric_check (b)) 00388 return qof_numeric_error (QOF_ERROR_ARG); 00389 00390 nb = b; 00391 nb.num = -nb.num; 00392 return qof_numeric_add (a, nb, denom, how); 00393 } 00394 00395 /* *************************************************************** 00396 * qof_numeric_mul 00397 *****************************************************************/ 00398 00399 QofNumeric 00400 qof_numeric_mul (QofNumeric a, QofNumeric b, gint64 denom, gint how) 00401 { 00402 QofNumeric product, result; 00403 QofInt128 bignume, bigdeno; 00404 00405 if (qof_numeric_check (a) || qof_numeric_check (b)) 00406 return qof_numeric_error (QOF_ERROR_ARG); 00407 00408 if ((denom == QOF_DENOM_AUTO) && 00409 (how & QOF_NUMERIC_DENOM_MASK) == QOF_HOW_DENOM_FIXED) 00410 { 00411 if (a.denom == b.denom) 00412 denom = a.denom; 00413 else if (b.num == 0) 00414 denom = a.denom; 00415 else if (a.num == 0) 00416 denom = b.denom; 00417 else 00418 return qof_numeric_error (QOF_ERROR_DENOM_DIFF); 00419 } 00420 00421 if ((denom == QOF_DENOM_AUTO) && 00422 ((how & QOF_NUMERIC_DENOM_MASK) == QOF_HOW_DENOM_LCD)) 00423 { 00424 denom = qof_numeric_lcd (a, b); 00425 how = how & QOF_NUMERIC_RND_MASK; 00426 } 00427 00428 if (a.denom < 0) 00429 { 00430 a.num *= -a.denom; /* BUG: overflow not handled. */ 00431 a.denom = 1; 00432 } 00433 00434 if (b.denom < 0) 00435 { 00436 b.num *= -b.denom; /* BUG: overflow not handled. */ 00437 b.denom = 1; 00438 } 00439 00440 bignume = mult128 (a.num, b.num); 00441 bigdeno = mult128 (a.denom, b.denom); 00442 product.num = a.num * b.num; 00443 product.denom = a.denom * b.denom; 00444 00445 /* If it looks to be overflowing, try to reduce the fraction ... */ 00446 if (bignume.isbig || bigdeno.isbig) 00447 { 00448 gint64 tmp; 00449 00450 a = qof_numeric_reduce (a); 00451 b = qof_numeric_reduce (b); 00452 tmp = a.num; 00453 a.num = b.num; 00454 b.num = tmp; 00455 a = qof_numeric_reduce (a); 00456 b = qof_numeric_reduce (b); 00457 bignume = mult128 (a.num, b.num); 00458 bigdeno = mult128 (a.denom, b.denom); 00459 product.num = a.num * b.num; 00460 product.denom = a.denom * b.denom; 00461 } 00462 00463 /* If it its still overflowing, and rounding is allowed then round */ 00464 if (bignume.isbig || bigdeno.isbig) 00465 { 00466 /* If rounding allowed, then shift until there's no 00467 * more overflow. The conversion at the end will fix 00468 * things up for the final value. Else overflow. */ 00469 if ((how & QOF_NUMERIC_RND_MASK) == QOF_HOW_RND_NEVER) 00470 { 00471 if (bigdeno.isbig) 00472 return qof_numeric_error (QOF_ERROR_OVERFLOW); 00473 product = reduce128 (bignume, product.denom); 00474 if (qof_numeric_check (product)) 00475 return qof_numeric_error (QOF_ERROR_OVERFLOW); 00476 } 00477 else 00478 { 00479 while (bignume.isbig || bigdeno.isbig) 00480 { 00481 bignume = shift128 (bignume); 00482 bigdeno = shift128 (bigdeno); 00483 } 00484 product.num = bignume.lo; 00485 if (bignume.isneg) 00486 product.num = -product.num; 00487 00488 product.denom = bigdeno.lo; 00489 if (0 == product.denom) 00490 return qof_numeric_error (QOF_ERROR_OVERFLOW); 00491 } 00492 } 00493 00494 #if 0 /* currently, product denom won't ever be zero */ 00495 if (product.denom < 0) 00496 { 00497 product.num = -product.num; 00498 product.denom = -product.denom; 00499 } 00500 #endif 00501 00502 result = qof_numeric_convert (product, denom, how); 00503 return result; 00504 } 00505 00506 /* ******************************************************************* 00507 * qof_numeric_div 00508 ********************************************************************/ 00509 00510 QofNumeric 00511 qof_numeric_div (QofNumeric a, QofNumeric b, gint64 denom, gint how) 00512 { 00513 QofNumeric quotient; 00514 QofInt128 nume, deno; 00515 00516 if (qof_numeric_check (a) || qof_numeric_check (b)) 00517 return qof_numeric_error (QOF_ERROR_ARG); 00518 00519 if ((denom == QOF_DENOM_AUTO) && 00520 (how & QOF_NUMERIC_DENOM_MASK) == QOF_HOW_DENOM_FIXED) 00521 { 00522 if (a.denom == b.denom) 00523 denom = a.denom; 00524 else if (a.denom == 0) 00525 denom = b.denom; 00526 else 00527 return qof_numeric_error (QOF_ERROR_DENOM_DIFF); 00528 } 00529 00530 if (a.denom < 0) 00531 { 00532 a.num *= -a.denom; /* BUG: overflow not handled. */ 00533 a.denom = 1; 00534 } 00535 00536 if (b.denom < 0) 00537 { 00538 b.num *= -b.denom; /* BUG: overflow not handled. */ 00539 b.denom = 1; 00540 } 00541 00542 if (a.denom == b.denom) 00543 { 00544 quotient.num = a.num; 00545 quotient.denom = b.num; 00546 } 00547 else 00548 { 00549 gint64 sgn = 1; 00550 if (0 > a.num) 00551 { 00552 sgn = -sgn; 00553 a.num = -a.num; 00554 } 00555 if (0 > b.num) 00556 { 00557 sgn = -sgn; 00558 b.num = -b.num; 00559 } 00560 nume = mult128 (a.num, b.denom); 00561 deno = mult128 (b.num, a.denom); 00562 00563 /* Try to avoid overflow by removing common factors */ 00564 if (nume.isbig && deno.isbig) 00565 { 00566 QofNumeric ra = qof_numeric_reduce (a); 00567 QofNumeric rb = qof_numeric_reduce (b); 00568 gint64 gcf_nume = gcf64 (ra.num, rb.num); 00569 gint64 gcf_deno = gcf64 (rb.denom, ra.denom); 00570 00571 nume = mult128 (ra.num / gcf_nume, rb.denom / gcf_deno); 00572 deno = mult128 (rb.num / gcf_nume, ra.denom / gcf_deno); 00573 } 00574 00575 if ((0 == nume.isbig) && (0 == deno.isbig)) 00576 { 00577 quotient.num = sgn * nume.lo; 00578 quotient.denom = deno.lo; 00579 goto dive_done; 00580 } 00581 else if (0 == deno.isbig) 00582 { 00583 quotient = reduce128 (nume, deno.lo); 00584 if (0 == qof_numeric_check (quotient)) 00585 { 00586 quotient.num *= sgn; 00587 goto dive_done; 00588 } 00589 } 00590 00591 /* If rounding allowed, then shift until there's no 00592 * more overflow. The conversion at the end will fix 00593 * things up for the final value. */ 00594 if ((how & QOF_NUMERIC_RND_MASK) == QOF_HOW_RND_NEVER) 00595 return qof_numeric_error (QOF_ERROR_OVERFLOW); 00596 while (nume.isbig || deno.isbig) 00597 { 00598 nume = shift128 (nume); 00599 deno = shift128 (deno); 00600 } 00601 quotient.num = sgn * nume.lo; 00602 quotient.denom = deno.lo; 00603 if (0 == quotient.denom) 00604 { 00605 return qof_numeric_error (QOF_ERROR_OVERFLOW); 00606 } 00607 } 00608 00609 if (quotient.denom < 0) 00610 { 00611 quotient.num = -quotient.num; 00612 quotient.denom = -quotient.denom; 00613 } 00614 00615 dive_done: 00616 if ((denom == QOF_DENOM_AUTO) && 00617 ((how & QOF_NUMERIC_DENOM_MASK) == QOF_HOW_DENOM_LCD)) 00618 { 00619 denom = qof_numeric_lcd (a, b); 00620 how = how & QOF_NUMERIC_RND_MASK; 00621 } 00622 00623 return qof_numeric_convert (quotient, denom, how); 00624 } 00625 00626 /* ******************************************************************* 00627 * qof_numeric_neg 00628 * negate the argument 00629 ********************************************************************/ 00630 00631 QofNumeric 00632 qof_numeric_neg (QofNumeric a) 00633 { 00634 if (qof_numeric_check (a)) 00635 return qof_numeric_error (QOF_ERROR_ARG); 00636 return qof_numeric_create (-a.num, a.denom); 00637 } 00638 00639 /* ******************************************************************* 00640 * qof_numeric_neg 00641 * return the absolute value of the argument 00642 ********************************************************************/ 00643 00644 QofNumeric 00645 qof_numeric_abs (QofNumeric a) 00646 { 00647 if (qof_numeric_check (a)) 00648 return qof_numeric_error (QOF_ERROR_ARG); 00649 return qof_numeric_create (ABS (a.num), a.denom); 00650 } 00651 00652 /* ******************************************************************* 00653 * qof_numeric_convert 00654 ********************************************************************/ 00655 00656 QofNumeric 00657 qof_numeric_convert (QofNumeric in, gint64 denom, gint how) 00658 { 00659 QofNumeric out; 00660 QofNumeric temp; 00661 gint64 temp_bc; 00662 gint64 temp_a; 00663 gint64 remainder; 00664 gint64 sign; 00665 gint denom_neg = 0; 00666 gdouble ratio, logratio; 00667 gdouble sigfigs; 00668 QofInt128 nume, newm; 00669 00670 temp.num = 0; 00671 temp.denom = 0; 00672 00673 if (qof_numeric_check (in)) 00674 return qof_numeric_error (QOF_ERROR_ARG); 00675 00676 if (denom == QOF_DENOM_AUTO) 00677 { 00678 switch (how & QOF_NUMERIC_DENOM_MASK) 00679 { 00680 default: 00681 case QOF_HOW_DENOM_LCD: /* LCD is meaningless with AUTO in here */ 00682 case QOF_HOW_DENOM_EXACT: 00683 return in; 00684 break; 00685 00686 case QOF_HOW_DENOM_REDUCE: 00687 /* reduce the input to a relatively-prime fraction */ 00688 return qof_numeric_reduce (in); 00689 break; 00690 00691 case QOF_HOW_DENOM_FIXED: 00692 if (in.denom != denom) 00693 return qof_numeric_error (QOF_ERROR_DENOM_DIFF); 00694 else 00695 return in; 00696 break; 00697 00698 case QOF_HOW_DENOM_SIGFIG: 00699 ratio = fabs (qof_numeric_to_double (in)); 00700 if (ratio < 10e-20) 00701 logratio = 0; 00702 else 00703 { 00704 logratio = log10 (ratio); 00705 logratio = ((logratio > 0.0) ? 00706 (floor (logratio) + 1.0) : (ceil (logratio))); 00707 } 00708 sigfigs = QOF_HOW_GET_SIGFIGS (how); 00709 00710 if (sigfigs - logratio >= 0) 00711 denom = (gint64) (pow (10, sigfigs - logratio)); 00712 else 00713 denom = -((gint64) (pow (10, logratio - sigfigs))); 00714 00715 how = how & ~QOF_HOW_DENOM_SIGFIG & ~QOF_NUMERIC_SIGFIGS_MASK; 00716 break; 00717 } 00718 } 00719 00720 /* Make sure we need to do the work */ 00721 if (in.denom == denom) 00722 return in; 00723 if (in.num == 0) 00724 { 00725 out.num = 0; 00726 out.denom = denom; 00727 return out; 00728 } 00729 00730 /* If the denominator of the input value is negative, get rid of that. */ 00731 if (in.denom < 0) 00732 { 00733 in.num = in.num * (-in.denom); /* BUG: overflow not handled. */ 00734 in.denom = 1; 00735 } 00736 00737 sign = (in.num < 0) ? -1 : 1; 00738 00739 /* If the denominator is less than zero, we are to interpret it as 00740 * the reciprocal of its magnitude. */ 00741 if (denom < 0) 00742 { 00743 00744 /* XXX FIXME: use 128-bit math here ... */ 00745 denom = -denom; 00746 denom_neg = 1; 00747 temp_a = (in.num < 0) ? -in.num : in.num; 00748 temp_bc = in.denom * denom; /* BUG: overflow not handled. */ 00749 remainder = temp_a % temp_bc; 00750 out.num = temp_a / temp_bc; 00751 out.denom = -denom; 00752 } 00753 else 00754 { 00755 /* Do all the modulo and int division on positive values to make 00756 * things a little clearer. Reduce the fraction denom/in.denom to 00757 * help with range errors */ 00758 temp.num = denom; 00759 temp.denom = in.denom; 00760 temp = qof_numeric_reduce (temp); 00761 00762 /* Symbolically, do the following: 00763 * out.num = in.num * temp.num; 00764 * remainder = out.num % temp.denom; 00765 * out.num = out.num / temp.denom; 00766 * out.denom = denom; 00767 */ 00768 nume = mult128 (in.num, temp.num); 00769 newm = div128 (nume, temp.denom); 00770 remainder = rem128 (nume, temp.denom); 00771 00772 if (newm.isbig) 00773 return qof_numeric_error (QOF_ERROR_OVERFLOW); 00774 00775 out.num = newm.lo; 00776 out.denom = denom; 00777 } 00778 00779 if (remainder) 00780 { 00781 switch (how & QOF_NUMERIC_RND_MASK) 00782 { 00783 case QOF_HOW_RND_FLOOR: 00784 if (sign < 0) 00785 out.num = out.num + 1; 00786 break; 00787 00788 case QOF_HOW_RND_CEIL: 00789 if (sign > 0) 00790 out.num = out.num + 1; 00791 break; 00792 00793 case QOF_HOW_RND_TRUNC: 00794 break; 00795 00796 case QOF_HOW_RND_PROMOTE: 00797 out.num = out.num + 1; 00798 break; 00799 00800 case QOF_HOW_RND_ROUND_HALF_DOWN: 00801 if (denom_neg) 00802 { 00803 if ((2 * remainder) > in.denom * denom) 00804 out.num = out.num + 1; 00805 } 00806 else if ((2 * remainder) > temp.denom) 00807 out.num = out.num + 1; 00808 /* check that 2*remainder didn't over-flow */ 00809 else if (((2 * remainder) < remainder) && 00810 (remainder > (temp.denom / 2))) 00811 out.num = out.num + 1; 00812 break; 00813 00814 case QOF_HOW_RND_ROUND_HALF_UP: 00815 if (denom_neg) 00816 { 00817 if ((2 * remainder) >= in.denom * denom) 00818 out.num = out.num + 1; 00819 } 00820 else if ((2 * remainder) >= temp.denom) 00821 out.num = out.num + 1; 00822 /* check that 2*remainder didn't over-flow */ 00823 else if (((2 * remainder) < remainder) && 00824 (remainder >= (temp.denom / 2))) 00825 out.num = out.num + 1; 00826 break; 00827 00828 case QOF_HOW_RND_ROUND: 00829 if (denom_neg) 00830 { 00831 if ((2 * remainder) > in.denom * denom) 00832 out.num = out.num + 1; 00833 else if ((2 * remainder) == in.denom * denom) 00834 { 00835 if (out.num % 2) 00836 out.num = out.num + 1; 00837 } 00838 } 00839 else 00840 { 00841 if ((2 * remainder) > temp.denom) 00842 out.num = out.num + 1; 00843 /* check that 2*remainder didn't over-flow */ 00844 else if (((2 * remainder) < remainder) && 00845 (remainder > (temp.denom / 2))) 00846 { 00847 out.num = out.num + 1; 00848 } 00849 else if ((2 * remainder) == temp.denom) 00850 { 00851 if (out.num % 2) 00852 out.num = out.num + 1; 00853 } 00854 /* check that 2*remainder didn't over-flow */ 00855 else if (((2 * remainder) < remainder) && 00856 (remainder == (temp.denom / 2))) 00857 { 00858 if (out.num % 2) 00859 out.num = out.num + 1; 00860 } 00861 } 00862 break; 00863 00864 case QOF_HOW_RND_NEVER: 00865 return qof_numeric_error (QOF_ERROR_REMAINDER); 00866 break; 00867 } 00868 } 00869 00870 out.num = (sign > 0) ? out.num : (-out.num); 00871 00872 return out; 00873 } 00874 00875 /* ************************************************************* 00876 reduce a fraction by GCF elimination. This is NOT done as a 00877 part of the arithmetic API unless QOF_HOW_DENOM_REDUCE is 00878 specified 00879 as the output denominator. 00880 ****************************************************************/ 00881 00882 QofNumeric 00883 qof_numeric_reduce (QofNumeric in) 00884 { 00885 gint64 t; 00886 gint64 num = (in.num < 0) ? (-in.num) : in.num; 00887 gint64 denom = in.denom; 00888 QofNumeric out; 00889 00890 if (qof_numeric_check (in)) 00891 return qof_numeric_error (QOF_ERROR_ARG); 00892 00893 /* The strategy is to use Euclid's algorithm */ 00894 while (denom > 0) 00895 { 00896 t = num % denom; 00897 num = denom; 00898 denom = t; 00899 } 00900 /* num now holds the GCD (Greatest Common Divisor) */ 00901 00902 /* All calculations are done on positive num, since it's not 00903 * well defined what % does for negative values */ 00904 out.num = in.num / num; 00905 out.denom = in.denom / num; 00906 return out; 00907 } 00908 00909 /* *************************************************************** 00910 * double_to_QofNumeric 00911 ****************************************************************/ 00912 00913 QofNumeric 00914 qof_numeric_from_double (gdouble in, gint64 denom, gint how) 00915 { 00916 QofNumeric out; 00917 gint64 int_part = 0; 00918 gdouble frac_part; 00919 gint64 frac_int = 0; 00920 gdouble logval; 00921 gdouble sigfigs; 00922 00923 if ((denom == QOF_DENOM_AUTO) && (how & QOF_HOW_DENOM_SIGFIG)) 00924 { 00925 if (fabs (in) < 10e-20) 00926 logval = 0; 00927 else 00928 { 00929 logval = log10 (fabs (in)); 00930 logval = ((logval > 0.0) ? 00931 (floor (logval) + 1.0) : (ceil (logval))); 00932 } 00933 sigfigs = QOF_HOW_GET_SIGFIGS (how); 00934 if (sigfigs - logval >= 0) 00935 denom = (gint64) (pow (10, sigfigs - logval)); 00936 else 00937 denom = -((gint64) (pow (10, logval - sigfigs))); 00938 00939 how = how & ~QOF_HOW_DENOM_SIGFIG & ~QOF_NUMERIC_SIGFIGS_MASK; 00940 } 00941 00942 int_part = (gint64) (floor (fabs (in))); 00943 frac_part = in - (double) int_part; 00944 00945 int_part = int_part * denom; 00946 frac_part = frac_part * (double) denom; 00947 00948 switch (how & QOF_NUMERIC_RND_MASK) 00949 { 00950 case QOF_HOW_RND_FLOOR: 00951 frac_int = (gint64) floor (frac_part); 00952 break; 00953 00954 case QOF_HOW_RND_CEIL: 00955 frac_int = (gint64) ceil (frac_part); 00956 break; 00957 00958 case QOF_HOW_RND_TRUNC: 00959 frac_int = (gint64) frac_part; 00960 break; 00961 00962 case QOF_HOW_RND_ROUND: 00963 case QOF_HOW_RND_ROUND_HALF_UP: 00964 frac_int = (gint64) rint (frac_part); 00965 break; 00966 00967 case QOF_HOW_RND_NEVER: 00968 frac_int = (gint64) floor (frac_part); 00969 if (frac_part != (double) frac_int) 00970 { 00971 /* signal an error */ 00972 } 00973 break; 00974 } 00975 00976 out.num = int_part + frac_int; 00977 out.denom = denom; 00978 return out; 00979 } 00980 00981 /* ******************************************************************* 00982 * qof_numeric_to_double 00983 ********************************************************************/ 00984 00985 gdouble 00986 qof_numeric_to_double (QofNumeric in) 00987 { 00988 if (in.denom > 0) 00989 return (gdouble) in.num / (gdouble) in.denom; 00990 else 00991 return (gdouble) (in.num * -in.denom); 00992 } 00993 00994 /* ******************************************************************* 00995 * qof_numeric_error 00996 ********************************************************************/ 00997 00998 QofNumeric 00999 qof_numeric_error (QofNumericErrorCode error_code) 01000 { 01001 return qof_numeric_create (error_code, 0LL); 01002 } 01003 01004 /* ******************************************************************* 01005 * qof_numeric_add_with_error 01006 ********************************************************************/ 01007 01008 QofNumeric 01009 qof_numeric_add_with_error (QofNumeric a, QofNumeric b, 01010 gint64 denom, gint how, QofNumeric * error) 01011 { 01012 01013 QofNumeric sum = qof_numeric_add (a, b, denom, how); 01014 QofNumeric exact = qof_numeric_add (a, b, QOF_DENOM_AUTO, 01015 QOF_HOW_DENOM_REDUCE); 01016 QofNumeric err = qof_numeric_sub (sum, exact, QOF_DENOM_AUTO, 01017 QOF_HOW_DENOM_REDUCE); 01018 01019 if (error) 01020 *error = err; 01021 return sum; 01022 } 01023 01024 /* ******************************************************************* 01025 * qof_numeric_sub_with_error 01026 ********************************************************************/ 01027 01028 QofNumeric 01029 qof_numeric_sub_with_error (QofNumeric a, QofNumeric b, 01030 gint64 denom, gint how, QofNumeric * error) 01031 { 01032 QofNumeric diff = qof_numeric_sub (a, b, denom, how); 01033 QofNumeric exact = qof_numeric_sub (a, b, QOF_DENOM_AUTO, 01034 QOF_HOW_DENOM_REDUCE); 01035 QofNumeric err = qof_numeric_sub (diff, exact, QOF_DENOM_AUTO, 01036 QOF_HOW_DENOM_REDUCE); 01037 if (error) 01038 *error = err; 01039 return diff; 01040 } 01041 01042 /* ******************************************************************* 01043 * qof_numeric_mul_with_error 01044 ********************************************************************/ 01045 01046 QofNumeric 01047 qof_numeric_mul_with_error (QofNumeric a, QofNumeric b, 01048 gint64 denom, gint how, QofNumeric * error) 01049 { 01050 QofNumeric prod = qof_numeric_mul (a, b, denom, how); 01051 QofNumeric exact = qof_numeric_mul (a, b, QOF_DENOM_AUTO, 01052 QOF_HOW_DENOM_REDUCE); 01053 QofNumeric err = qof_numeric_sub (prod, exact, QOF_DENOM_AUTO, 01054 QOF_HOW_DENOM_REDUCE); 01055 if (error) 01056 *error = err; 01057 return prod; 01058 } 01059 01060 01061 /* ******************************************************************* 01062 * qof_numeric_div_with_error 01063 ********************************************************************/ 01064 01065 QofNumeric 01066 qof_numeric_div_with_error (QofNumeric a, QofNumeric b, 01067 gint64 denom, gint how, QofNumeric * error) 01068 { 01069 QofNumeric quot = qof_numeric_div (a, b, denom, how); 01070 QofNumeric exact = qof_numeric_div (a, b, QOF_DENOM_AUTO, 01071 QOF_HOW_DENOM_REDUCE); 01072 QofNumeric err = qof_numeric_sub (quot, exact, 01073 QOF_DENOM_AUTO, QOF_HOW_DENOM_REDUCE); 01074 if (error) 01075 *error = err; 01076 return quot; 01077 } 01078 01079 /* *************************************************************** 01080 * QofNumeric text IO 01081 ****************************************************************/ 01082 01083 gchar * 01084 qof_numeric_to_string (QofNumeric n) 01085 { 01086 gchar *result; 01087 gint64 tmpnum = n.num; 01088 gint64 tmpdenom = n.denom; 01089 01090 result = 01091 g_strdup_printf ("%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, tmpnum, 01092 tmpdenom); 01093 01094 return result; 01095 } 01096 01097 gchar * 01098 qof_numeric_dbg_to_string (QofNumeric n) 01099 { 01100 static gchar buff[1000]; 01101 static gchar *p = buff; 01102 gint64 tmpnum = n.num; 01103 gint64 tmpdenom = n.denom; 01104 01105 p += 100; 01106 if (p - buff >= 1000) 01107 p = buff; 01108 01109 sprintf (p, "%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, tmpnum, 01110 tmpdenom); 01111 01112 return p; 01113 } 01114 01115 gboolean 01116 qof_numeric_from_string (const gchar * str, QofNumeric * n) 01117 { 01118 size_t G_GNUC_UNUSED num_read; 01119 gint64 tmpnum; 01120 gint64 tmpdenom; 01121 01122 if (!str) 01123 return FALSE; 01124 tmpnum = strtoll (str, NULL, 0); 01125 str = strchr (str, '/'); 01126 if (!str) 01127 return FALSE; 01128 str++; 01129 tmpdenom = strtoll (str, NULL, 0); 01130 num_read = strspn (str, "0123456789"); 01131 n->num = tmpnum; 01132 n->denom = tmpdenom; 01133 return TRUE; 01134 } 01135 01136 /* ======================== END OF FILE =================== */