|
GnuCash 2.4.99
|
00001 /******************************************************************** 00002 * gnc-numeric.c -- an exact-number library for accounting use * 00003 * Copyright (C) 2000 Bill Gribble * 00004 * Copyright (C) 2004 Linas Vepstas <linas@linas.org> * 00005 * * 00006 * This program is free software; you can redistribute it and/or * 00007 * modify it under the terms of the GNU General Public License as * 00008 * published by the Free Software Foundation; either version 2 of * 00009 * the License, or (at your option) any later version. * 00010 * * 00011 * This program is distributed in the hope that it will be useful, * 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00014 * GNU General Public License for more details. * 00015 * * 00016 * You should have received a copy of the GNU General Public License* 00017 * along with this program; if not, contact: * 00018 * * 00019 * Free Software Foundation Voice: +1-617-542-5942 * 00020 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 * 00021 * Boston, MA 02110-1301, USA gnu@gnu.org * 00022 * * 00023 *******************************************************************/ 00024 00025 #include "config.h" 00026 00027 #include <glib.h> 00028 #include <math.h> 00029 #if defined(G_OS_WIN32) && !defined(_MSC_VER) 00030 # ifdef HAVE_POW_H 00031 # include <pow.h> 00032 # endif 00033 #endif 00034 #include <stdio.h> 00035 #include <stdlib.h> 00036 #include <string.h> 00037 00038 #include "gnc-numeric.h" 00039 00040 /* Note: The qofmath128 functions are used mostly here and almost 00041 nowhere else. Hence, we inline the C code directly into here so 00042 that the compiler can potentially inline the code as-is and speed 00043 up the gnc-numeric.c functions. */ 00044 #include "qofmath128.c" 00045 00046 /* static short module = MOD_ENGINE; */ 00047 00048 /* =============================================================== */ 00049 00050 #if 0 00051 static const char * _numeric_error_strings[] = 00052 { 00053 "No error", 00054 "Argument is not a valid number", 00055 "Intermediate result overflow", 00056 "Argument denominators differ in GNC_HOW_DENOM_FIXED operation", 00057 "Remainder part in GNC_HOW_RND_NEVER operation" 00058 }; 00059 #endif 00060 00061 /* =============================================================== */ 00062 /* This function is small, simple, and used everywhere below, 00063 * lets try to inline it. 00064 */ 00065 inline GNCNumericErrorCode 00066 gnc_numeric_check(gnc_numeric in) 00067 { 00068 if (G_LIKELY(in.denom != 0)) 00069 { 00070 return GNC_ERROR_OK; 00071 } 00072 else if (in.num) 00073 { 00074 if ((0 < in.num) || (-4 > in.num)) 00075 { 00076 in.num = (gint64) GNC_ERROR_OVERFLOW; 00077 } 00078 return (GNCNumericErrorCode) in.num; 00079 } 00080 else 00081 { 00082 return GNC_ERROR_ARG; 00083 } 00084 } 00085 00086 /* 00087 * Find the least common multiple of the denominators of a and b. 00088 */ 00089 00090 static inline gint64 00091 gnc_numeric_lcd(gnc_numeric a, gnc_numeric b) 00092 { 00093 qofint128 lcm; 00094 if (gnc_numeric_check(a) || gnc_numeric_check(b)) 00095 { 00096 return GNC_ERROR_ARG; 00097 } 00098 00099 if (b.denom == a.denom) return a.denom; 00100 00101 /* Special case: smaller divides smoothly into larger */ 00102 if ((b.denom < a.denom) && ((a.denom % b.denom) == 0)) 00103 { 00104 return a.denom; 00105 } 00106 if ((a.denom < b.denom) && ((b.denom % a.denom) == 0)) 00107 { 00108 return b.denom; 00109 } 00110 00111 lcm = lcm128 (a.denom, b.denom); 00112 if (lcm.isbig) return GNC_ERROR_ARG; 00113 return lcm.lo; 00114 } 00115 00116 00117 /* Return the ratio n/d reduced so that there are no common factors. */ 00118 static inline gnc_numeric 00119 reduce128(qofint128 n, gint64 d) 00120 { 00121 gint64 t; 00122 gint64 num; 00123 gint64 denom; 00124 gnc_numeric out; 00125 qofint128 red; 00126 00127 t = rem128 (n, d); 00128 num = d; 00129 denom = t; 00130 00131 /* The strategy is to use Euclid's algorithm */ 00132 while (denom > 0) 00133 { 00134 t = num % denom; 00135 num = denom; 00136 denom = t; 00137 } 00138 /* num now holds the GCD (Greatest Common Divisor) */ 00139 00140 red = div128 (n, num); 00141 if (red.isbig) 00142 { 00143 return gnc_numeric_error (GNC_ERROR_OVERFLOW); 00144 } 00145 out.num = red.lo; 00146 if (red.isneg) out.num = -out.num; 00147 out.denom = d / num; 00148 return out; 00149 } 00150 00151 /* ******************************************************************* 00152 * gnc_numeric_zero_p 00153 ********************************************************************/ 00154 00155 gboolean 00156 gnc_numeric_zero_p(gnc_numeric a) 00157 { 00158 if (gnc_numeric_check(a)) 00159 { 00160 return 0; 00161 } 00162 else 00163 { 00164 if ((a.num == 0) && (a.denom != 0)) 00165 { 00166 return 1; 00167 } 00168 else 00169 { 00170 return 0; 00171 } 00172 } 00173 } 00174 00175 /* ******************************************************************* 00176 * gnc_numeric_negative_p 00177 ********************************************************************/ 00178 00179 gboolean 00180 gnc_numeric_negative_p(gnc_numeric a) 00181 { 00182 if (gnc_numeric_check(a)) 00183 { 00184 return 0; 00185 } 00186 else 00187 { 00188 if ((a.num < 0) && (a.denom != 0)) 00189 { 00190 return 1; 00191 } 00192 else 00193 { 00194 return 0; 00195 } 00196 } 00197 } 00198 00199 /* ******************************************************************* 00200 * gnc_numeric_positive_p 00201 ********************************************************************/ 00202 00203 gboolean 00204 gnc_numeric_positive_p(gnc_numeric a) 00205 { 00206 if (gnc_numeric_check(a)) 00207 { 00208 return 0; 00209 } 00210 else 00211 { 00212 if ((a.num > 0) && (a.denom != 0)) 00213 { 00214 return 1; 00215 } 00216 else 00217 { 00218 return 0; 00219 } 00220 } 00221 } 00222 00223 /* ******************************************************************* 00224 * gnc_numeric_compare 00225 * returns 1 if a>b, -1 if b>a, 0 if a == b 00226 ********************************************************************/ 00227 00228 int 00229 gnc_numeric_compare(gnc_numeric a, gnc_numeric b) 00230 { 00231 gint64 aa, bb; 00232 qofint128 l, r; 00233 00234 if (gnc_numeric_check(a) || gnc_numeric_check(b)) 00235 { 00236 return 0; 00237 } 00238 00239 if (a.denom == b.denom) 00240 { 00241 if (a.num == b.num) return 0; 00242 if (a.num > b.num) return 1; 00243 return -1; 00244 } 00245 00246 if ((a.denom > 0) && (b.denom > 0)) 00247 { 00248 /* Avoid overflows using 128-bit intermediate math */ 00249 l = mult128 (a.num, b.denom); 00250 r = mult128 (b.num, a.denom); 00251 return cmp128 (l, r); 00252 } 00253 00254 if (a.denom < 0) 00255 a.denom *= -1; 00256 if (b.denom < 0) 00257 b.denom *= -1; 00258 00259 /* BUG: Possible overflow here.. Also, doesn't properly deal with 00260 * reciprocal denominators. 00261 */ 00262 aa = a.num * a.denom; 00263 bb = b.num * b.denom; 00264 00265 if (aa == bb) return 0; 00266 if (aa > bb) return 1; 00267 return -1; 00268 } 00269 00270 00271 /* ******************************************************************* 00272 * gnc_numeric_eq 00273 ********************************************************************/ 00274 00275 gboolean 00276 gnc_numeric_eq(gnc_numeric a, gnc_numeric b) 00277 { 00278 return ((a.num == b.num) && (a.denom == b.denom)); 00279 } 00280 00281 00282 /* ******************************************************************* 00283 * gnc_numeric_equal 00284 ********************************************************************/ 00285 00286 gboolean 00287 gnc_numeric_equal(gnc_numeric a, gnc_numeric b) 00288 { 00289 qofint128 l, r; 00290 if ((a.denom == b.denom) && (a.denom > 0)) 00291 { 00292 return (a.num == b.num); 00293 } 00294 if ((a.denom > 0) && (b.denom > 0)) 00295 { 00296 // return (a.num*b.denom == b.num*a.denom); 00297 l = mult128 (a.num, b.denom); 00298 r = mult128 (b.num, a.denom); 00299 return equal128 (l, r); 00300 00301 #if ALT_WAY_OF_CHECKING_EQUALITY 00302 gnc_numeric ra = gnc_numeric_reduce (a); 00303 gnc_numeric rb = gnc_numeric_reduce (b); 00304 if (ra.denom != rb.denom) return 0; 00305 if (ra.num != rb.num) return 0; 00306 return 1; 00307 #endif 00308 } 00309 if ((a.denom < 0) && (b.denom < 0)) 00310 { 00311 l = mult128 (a.num, -a.denom); 00312 r = mult128 (b.num, -b.denom); 00313 return equal128 (l, r); 00314 } 00315 else 00316 { 00317 /* BUG: One of the numbers has a reciprocal denom, and the other 00318 does not. I just don't know to handle this case in any 00319 reasonably overflow-proof yet simple way. So, this function 00320 will simply get it wrong whenever the three multiplies 00321 overflow 64-bits. -CAS */ 00322 if (a.denom < 0) 00323 { 00324 return ((a.num * -a.denom * b.denom) == b.num); 00325 } 00326 else 00327 { 00328 return (a.num == (b.num * a.denom * -b.denom)); 00329 } 00330 } 00331 00332 return ((a.num * b.denom) == (a.denom * b.num)); 00333 } 00334 00335 00336 /* ******************************************************************* 00337 * gnc_numeric_same 00338 * would a and b be equal() if they were both converted to the same 00339 * denominator? 00340 ********************************************************************/ 00341 00342 int 00343 gnc_numeric_same(gnc_numeric a, gnc_numeric b, gint64 denom, 00344 gint how) 00345 { 00346 gnc_numeric aconv, bconv; 00347 00348 aconv = gnc_numeric_convert(a, denom, how); 00349 bconv = gnc_numeric_convert(b, denom, how); 00350 00351 return(gnc_numeric_equal(aconv, bconv)); 00352 } 00353 00354 00355 00356 /* ******************************************************************* 00357 * gnc_numeric_add 00358 ********************************************************************/ 00359 00360 gnc_numeric 00361 gnc_numeric_add(gnc_numeric a, gnc_numeric b, 00362 gint64 denom, gint how) 00363 { 00364 gnc_numeric sum; 00365 00366 if (gnc_numeric_check(a) || gnc_numeric_check(b)) 00367 { 00368 return gnc_numeric_error(GNC_ERROR_ARG); 00369 } 00370 00371 if ((denom == GNC_DENOM_AUTO) && 00372 (how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_FIXED) 00373 { 00374 if (a.denom == b.denom) 00375 { 00376 denom = a.denom; 00377 } 00378 else if (b.num == 0) 00379 { 00380 denom = a.denom; 00381 b.denom = a.denom; 00382 } 00383 else if (a.num == 0) 00384 { 00385 denom = b.denom; 00386 a.denom = b.denom; 00387 } 00388 else 00389 { 00390 return gnc_numeric_error(GNC_ERROR_DENOM_DIFF); 00391 } 00392 } 00393 00394 if (a.denom < 0) 00395 { 00396 a.num *= -a.denom; /* BUG: overflow not handled. */ 00397 a.denom = 1; 00398 } 00399 00400 if (b.denom < 0) 00401 { 00402 b.num *= -b.denom; /* BUG: overflow not handled. */ 00403 b.denom = 1; 00404 } 00405 00406 /* Get an exact answer.. same denominator is the common case. */ 00407 if (a.denom == b.denom) 00408 { 00409 sum.num = a.num + b.num; /* BUG: overflow not handled. */ 00410 sum.denom = a.denom; 00411 } 00412 else 00413 { 00414 /* We want to do this: 00415 * sum.num = a.num*b.denom + b.num*a.denom; 00416 * sum.denom = a.denom*b.denom; 00417 * but the multiply could overflow. 00418 * Computing the LCD minimizes likelihood of overflow 00419 */ 00420 gint64 lcd; 00421 qofint128 ca, cb, cab; 00422 lcd = gnc_numeric_lcd(a, b); 00423 if (GNC_ERROR_ARG == lcd) 00424 { 00425 return gnc_numeric_error(GNC_ERROR_OVERFLOW); 00426 } 00427 ca = mult128 (a.num, lcd / a.denom); 00428 if (ca.isbig) return gnc_numeric_error(GNC_ERROR_OVERFLOW); 00429 00430 cb = mult128 (b.num, lcd / b.denom); 00431 if (cb.isbig) return gnc_numeric_error(GNC_ERROR_OVERFLOW); 00432 00433 cab = add128 (ca, cb); 00434 if (cab.isbig) return gnc_numeric_error(GNC_ERROR_OVERFLOW); 00435 00436 sum.num = cab.lo; 00437 if (cab.isneg) sum.num = -sum.num; 00438 sum.denom = lcd; 00439 } 00440 00441 if ((denom == GNC_DENOM_AUTO) && 00442 ((how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_LCD)) 00443 { 00444 denom = gnc_numeric_lcd(a, b); 00445 how = how & GNC_NUMERIC_RND_MASK; 00446 } 00447 00448 return gnc_numeric_convert(sum, denom, how); 00449 } 00450 00451 /* ******************************************************************* 00452 * gnc_numeric_sub 00453 ********************************************************************/ 00454 00455 gnc_numeric 00456 gnc_numeric_sub(gnc_numeric a, gnc_numeric b, 00457 gint64 denom, gint how) 00458 { 00459 gnc_numeric nb; 00460 if (gnc_numeric_check(a) || gnc_numeric_check(b)) 00461 { 00462 return gnc_numeric_error(GNC_ERROR_ARG); 00463 } 00464 00465 nb = b; 00466 nb.num = -nb.num; 00467 return gnc_numeric_add (a, nb, denom, how); 00468 } 00469 00470 /* ******************************************************************* 00471 * gnc_numeric_mul 00472 ********************************************************************/ 00473 00474 gnc_numeric 00475 gnc_numeric_mul(gnc_numeric a, gnc_numeric b, 00476 gint64 denom, gint how) 00477 { 00478 gnc_numeric product, result; 00479 qofint128 bignume, bigdeno; 00480 00481 if (gnc_numeric_check(a) || gnc_numeric_check(b)) 00482 { 00483 return gnc_numeric_error(GNC_ERROR_ARG); 00484 } 00485 00486 if ((denom == GNC_DENOM_AUTO) && 00487 (how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_FIXED) 00488 { 00489 if (a.denom == b.denom) 00490 { 00491 denom = a.denom; 00492 } 00493 else if (b.num == 0) 00494 { 00495 denom = a.denom; 00496 } 00497 else if (a.num == 0) 00498 { 00499 denom = b.denom; 00500 } 00501 else 00502 { 00503 return gnc_numeric_error(GNC_ERROR_DENOM_DIFF); 00504 } 00505 } 00506 00507 if ((denom == GNC_DENOM_AUTO) && 00508 ((how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_LCD)) 00509 { 00510 denom = gnc_numeric_lcd(a, b); 00511 how = how & GNC_NUMERIC_RND_MASK; 00512 } 00513 00514 if (a.denom < 0) 00515 { 00516 a.num *= -a.denom; /* BUG: overflow not handled. */ 00517 a.denom = 1; 00518 } 00519 00520 if (b.denom < 0) 00521 { 00522 b.num *= -b.denom; /* BUG: overflow not handled. */ 00523 b.denom = 1; 00524 } 00525 00526 bignume = mult128 (a.num, b.num); 00527 bigdeno = mult128 (a.denom, b.denom); 00528 product.num = a.num * b.num; 00529 product.denom = a.denom * b.denom; 00530 00531 /* If it looks to be overflowing, try to reduce the fraction ... */ 00532 if (bignume.isbig || bigdeno.isbig) 00533 { 00534 gint64 tmp; 00535 a = gnc_numeric_reduce (a); 00536 b = gnc_numeric_reduce (b); 00537 tmp = a.num; 00538 a.num = b.num; 00539 b.num = tmp; 00540 a = gnc_numeric_reduce (a); 00541 b = gnc_numeric_reduce (b); 00542 00543 bignume = mult128 (a.num, b.num); 00544 bigdeno = mult128 (a.denom, b.denom); 00545 product.num = a.num * b.num; 00546 product.denom = a.denom * b.denom; 00547 } 00548 00549 /* If it its still overflowing, and rounding is allowed then round */ 00550 if (bignume.isbig || bigdeno.isbig) 00551 { 00552 /* If rounding allowed, then shift until there's no 00553 * more overflow. The conversion at the end will fix 00554 * things up for the final value. Else overflow. */ 00555 if ((how & GNC_NUMERIC_RND_MASK) == GNC_HOW_RND_NEVER) 00556 { 00557 if (bigdeno.isbig) 00558 { 00559 return gnc_numeric_error (GNC_ERROR_OVERFLOW); 00560 } 00561 product = reduce128 (bignume, product.denom); 00562 if (gnc_numeric_check (product)) 00563 { 00564 return gnc_numeric_error (GNC_ERROR_OVERFLOW); 00565 } 00566 } 00567 else 00568 { 00569 while (bignume.isbig || bigdeno.isbig) 00570 { 00571 bignume = shift128 (bignume); 00572 bigdeno = shift128 (bigdeno); 00573 } 00574 product.num = bignume.lo; 00575 if (bignume.isneg) product.num = -product.num; 00576 00577 product.denom = bigdeno.lo; 00578 if (0 == product.denom) 00579 { 00580 return gnc_numeric_error (GNC_ERROR_OVERFLOW); 00581 } 00582 } 00583 } 00584 00585 #if 0 /* currently, product denom won't ever be zero */ 00586 if (product.denom < 0) 00587 { 00588 product.num = -product.num; 00589 product.denom = -product.denom; 00590 } 00591 #endif 00592 00593 result = gnc_numeric_convert(product, denom, how); 00594 return result; 00595 } 00596 00597 00598 /* ******************************************************************* 00599 * gnc_numeric_div 00600 ********************************************************************/ 00601 00602 gnc_numeric 00603 gnc_numeric_div(gnc_numeric a, gnc_numeric b, 00604 gint64 denom, gint how) 00605 { 00606 gnc_numeric quotient; 00607 qofint128 nume, deno; 00608 00609 if (gnc_numeric_check(a) || gnc_numeric_check(b)) 00610 { 00611 return gnc_numeric_error(GNC_ERROR_ARG); 00612 } 00613 00614 if ((denom == GNC_DENOM_AUTO) && 00615 (how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_FIXED) 00616 { 00617 if (a.denom == b.denom) 00618 { 00619 denom = a.denom; 00620 } 00621 else if (a.denom == 0) 00622 { 00623 denom = b.denom; 00624 } 00625 else 00626 { 00627 return gnc_numeric_error(GNC_ERROR_DENOM_DIFF); 00628 } 00629 } 00630 00631 00632 if (a.denom < 0) 00633 { 00634 a.num *= -a.denom; /* BUG: overflow not handled. */ 00635 a.denom = 1; 00636 } 00637 00638 if (b.denom < 0) 00639 { 00640 b.num *= -b.denom; /* BUG: overflow not handled. */ 00641 b.denom = 1; 00642 } 00643 00644 if (a.denom == b.denom) 00645 { 00646 quotient.num = a.num; 00647 quotient.denom = b.num; 00648 } 00649 else 00650 { 00651 gint64 sgn = 1; 00652 if (0 > a.num) 00653 { 00654 sgn = -sgn; 00655 a.num = -a.num; 00656 } 00657 if (0 > b.num) 00658 { 00659 sgn = -sgn; 00660 b.num = -b.num; 00661 } 00662 nume = mult128(a.num, b.denom); 00663 deno = mult128(b.num, a.denom); 00664 00665 /* Try to avoid overflow by removing common factors */ 00666 if (nume.isbig && deno.isbig) 00667 { 00668 gnc_numeric ra = gnc_numeric_reduce (a); 00669 gnc_numeric rb = gnc_numeric_reduce (b); 00670 00671 gint64 gcf_nume = gcf64(ra.num, rb.num); 00672 gint64 gcf_deno = gcf64(rb.denom, ra.denom); 00673 nume = mult128(ra.num / gcf_nume, rb.denom / gcf_deno); 00674 deno = mult128(rb.num / gcf_nume, ra.denom / gcf_deno); 00675 } 00676 00677 if ((0 == nume.isbig) && (0 == deno.isbig)) 00678 { 00679 quotient.num = sgn * nume.lo; 00680 quotient.denom = deno.lo; 00681 goto dive_done; 00682 } 00683 else if (0 == deno.isbig) 00684 { 00685 quotient = reduce128 (nume, deno.lo); 00686 if (0 == gnc_numeric_check (quotient)) 00687 { 00688 quotient.num *= sgn; 00689 goto dive_done; 00690 } 00691 } 00692 00693 /* If rounding allowed, then shift until there's no 00694 * more overflow. The conversion at the end will fix 00695 * things up for the final value. */ 00696 if ((how & GNC_NUMERIC_RND_MASK) == GNC_HOW_RND_NEVER) 00697 { 00698 return gnc_numeric_error (GNC_ERROR_OVERFLOW); 00699 } 00700 while (nume.isbig || deno.isbig) 00701 { 00702 nume = shift128 (nume); 00703 deno = shift128 (deno); 00704 } 00705 quotient.num = sgn * nume.lo; 00706 quotient.denom = deno.lo; 00707 if (0 == quotient.denom) 00708 { 00709 return gnc_numeric_error (GNC_ERROR_OVERFLOW); 00710 } 00711 } 00712 00713 if (quotient.denom < 0) 00714 { 00715 quotient.num = -quotient.num; 00716 quotient.denom = -quotient.denom; 00717 } 00718 00719 dive_done: 00720 if ((denom == GNC_DENOM_AUTO) && 00721 ((how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_LCD)) 00722 { 00723 denom = gnc_numeric_lcd(a, b); 00724 how = how & GNC_NUMERIC_RND_MASK; 00725 } 00726 00727 return gnc_numeric_convert(quotient, denom, how); 00728 } 00729 00730 /* ******************************************************************* 00731 * gnc_numeric_neg 00732 * negate the argument 00733 ********************************************************************/ 00734 00735 gnc_numeric 00736 gnc_numeric_neg(gnc_numeric a) 00737 { 00738 if (gnc_numeric_check(a)) 00739 { 00740 return gnc_numeric_error(GNC_ERROR_ARG); 00741 } 00742 return gnc_numeric_create(- a.num, a.denom); 00743 } 00744 00745 /* ******************************************************************* 00746 * gnc_numeric_abs 00747 * return the absolute value of the argument 00748 ********************************************************************/ 00749 00750 gnc_numeric 00751 gnc_numeric_abs(gnc_numeric a) 00752 { 00753 if (gnc_numeric_check(a)) 00754 { 00755 return gnc_numeric_error(GNC_ERROR_ARG); 00756 } 00757 return gnc_numeric_create(ABS(a.num), a.denom); 00758 } 00759 00760 /* ******************************************************************* 00761 * gnc_numeric_convert 00762 ********************************************************************/ 00763 00764 gnc_numeric 00765 gnc_numeric_convert(gnc_numeric in, gint64 denom, gint how) 00766 { 00767 gnc_numeric out; 00768 gnc_numeric temp; 00769 gint64 temp_bc; 00770 gint64 temp_a; 00771 gint64 remainder; 00772 gint64 sign; 00773 gint denom_neg = 0; 00774 double ratio, logratio; 00775 double sigfigs; 00776 qofint128 nume, newm; 00777 00778 temp.num = 0; 00779 temp.denom = 0; 00780 00781 if (gnc_numeric_check(in)) 00782 { 00783 return gnc_numeric_error(GNC_ERROR_ARG); 00784 } 00785 00786 if (denom == GNC_DENOM_AUTO) 00787 { 00788 switch (how & GNC_NUMERIC_DENOM_MASK) 00789 { 00790 default: 00791 case GNC_HOW_DENOM_LCD: /* LCD is meaningless with AUTO in here */ 00792 case GNC_HOW_DENOM_EXACT: 00793 return in; 00794 break; 00795 00796 case GNC_HOW_DENOM_REDUCE: 00797 /* reduce the input to a relatively-prime fraction */ 00798 return gnc_numeric_reduce(in); 00799 break; 00800 00801 case GNC_HOW_DENOM_FIXED: 00802 if (in.denom != denom) 00803 { 00804 return gnc_numeric_error(GNC_ERROR_DENOM_DIFF); 00805 } 00806 else 00807 { 00808 return in; 00809 } 00810 break; 00811 00812 case GNC_HOW_DENOM_SIGFIG: 00813 ratio = fabs(gnc_numeric_to_double(in)); 00814 if (ratio < 10e-20) 00815 { 00816 logratio = 0; 00817 } 00818 else 00819 { 00820 logratio = log10(ratio); 00821 logratio = ((logratio > 0.0) ? 00822 (floor(logratio) + 1.0) : (ceil(logratio))); 00823 } 00824 sigfigs = GNC_HOW_GET_SIGFIGS(how); 00825 00826 if (fabs(sigfigs - logratio) > 18) 00827 return gnc_numeric_error(GNC_ERROR_OVERFLOW); 00828 00829 if (sigfigs - logratio >= 0) 00830 { 00831 denom = (gint64)(pow(10, sigfigs - logratio)); 00832 } 00833 else 00834 { 00835 denom = -((gint64)(pow(10, logratio - sigfigs))); 00836 } 00837 00838 how = how & ~GNC_HOW_DENOM_SIGFIG & ~GNC_NUMERIC_SIGFIGS_MASK; 00839 break; 00840 00841 } 00842 } 00843 00844 /* Make sure we need to do the work */ 00845 if (in.denom == denom) 00846 { 00847 return in; 00848 } 00849 if (in.num == 0) 00850 { 00851 out.num = 0; 00852 out.denom = denom; 00853 return out; 00854 } 00855 00856 /* If the denominator of the input value is negative, get rid of that. */ 00857 if (in.denom < 0) 00858 { 00859 in.num = in.num * (- in.denom); /* BUG: overflow not handled. */ 00860 in.denom = 1; 00861 } 00862 00863 sign = (in.num < 0) ? -1 : 1; 00864 00865 /* If the denominator is less than zero, we are to interpret it as 00866 * the reciprocal of its magnitude. */ 00867 if (denom < 0) 00868 { 00869 00870 /* XXX FIXME: use 128-bit math here ... */ 00871 denom = - denom; 00872 denom_neg = 1; 00873 temp_a = (in.num < 0) ? -in.num : in.num; 00874 temp_bc = in.denom * denom; /* BUG: overflow not handled. */ 00875 remainder = temp_a % temp_bc; 00876 out.num = temp_a / temp_bc; 00877 out.denom = - denom; 00878 } 00879 else 00880 { 00881 /* Do all the modulo and int division on positive values to make 00882 * things a little clearer. Reduce the fraction denom/in.denom to 00883 * help with range errors */ 00884 temp.num = denom; 00885 temp.denom = in.denom; 00886 temp = gnc_numeric_reduce(temp); 00887 00888 /* Symbolically, do the following: 00889 * out.num = in.num * temp.num; 00890 * remainder = out.num % temp.denom; 00891 * out.num = out.num / temp.denom; 00892 * out.denom = denom; 00893 */ 00894 nume = mult128 (in.num, temp.num); 00895 newm = div128 (nume, temp.denom); 00896 remainder = rem128 (nume, temp.denom); 00897 00898 if (newm.isbig) 00899 { 00900 return gnc_numeric_error(GNC_ERROR_OVERFLOW); 00901 } 00902 00903 out.num = newm.lo; 00904 out.denom = denom; 00905 } 00906 00907 if (remainder) 00908 { 00909 switch (how & GNC_NUMERIC_RND_MASK) 00910 { 00911 case GNC_HOW_RND_FLOOR: 00912 if (sign < 0) 00913 { 00914 out.num = out.num + 1; 00915 } 00916 break; 00917 00918 case GNC_HOW_RND_CEIL: 00919 if (sign > 0) 00920 { 00921 out.num = out.num + 1; 00922 } 00923 break; 00924 00925 case GNC_HOW_RND_TRUNC: 00926 break; 00927 00928 case GNC_HOW_RND_PROMOTE: 00929 out.num = out.num + 1; 00930 break; 00931 00932 case GNC_HOW_RND_ROUND_HALF_DOWN: 00933 if (denom_neg) 00934 { 00935 if ((2 * remainder) > in.denom * denom) 00936 { 00937 out.num = out.num + 1; 00938 } 00939 } 00940 else if ((2 * remainder) > temp.denom) 00941 { 00942 out.num = out.num + 1; 00943 } 00944 /* check that 2*remainder didn't over-flow */ 00945 else if (((2 * remainder) < remainder) && 00946 (remainder > (temp.denom / 2))) 00947 { 00948 out.num = out.num + 1; 00949 } 00950 break; 00951 00952 case GNC_HOW_RND_ROUND_HALF_UP: 00953 if (denom_neg) 00954 { 00955 if ((2 * remainder) >= in.denom * denom) 00956 { 00957 out.num = out.num + 1; 00958 } 00959 } 00960 else if ((2 * remainder ) >= temp.denom) 00961 { 00962 out.num = out.num + 1; 00963 } 00964 /* check that 2*remainder didn't over-flow */ 00965 else if (((2 * remainder) < remainder) && 00966 (remainder >= (temp.denom / 2))) 00967 { 00968 out.num = out.num + 1; 00969 } 00970 break; 00971 00972 case GNC_HOW_RND_ROUND: 00973 if (denom_neg) 00974 { 00975 if ((2 * remainder) > in.denom * denom) 00976 { 00977 out.num = out.num + 1; 00978 } 00979 else if ((2 * remainder) == in.denom * denom) 00980 { 00981 if (out.num % 2) 00982 { 00983 out.num = out.num + 1; 00984 } 00985 } 00986 } 00987 else 00988 { 00989 if ((2 * remainder ) > temp.denom) 00990 { 00991 out.num = out.num + 1; 00992 } 00993 /* check that 2*remainder didn't over-flow */ 00994 else if (((2 * remainder) < remainder) && 00995 (remainder > (temp.denom / 2))) 00996 { 00997 out.num = out.num + 1; 00998 } 00999 else if ((2 * remainder) == temp.denom) 01000 { 01001 if (out.num % 2) 01002 { 01003 out.num = out.num + 1; 01004 } 01005 } 01006 /* check that 2*remainder didn't over-flow */ 01007 else if (((2 * remainder) < remainder) && 01008 (remainder == (temp.denom / 2))) 01009 { 01010 if (out.num % 2) 01011 { 01012 out.num = out.num + 1; 01013 } 01014 } 01015 } 01016 break; 01017 01018 case GNC_HOW_RND_NEVER: 01019 return gnc_numeric_error(GNC_ERROR_REMAINDER); 01020 break; 01021 } 01022 } 01023 01024 out.num = (sign > 0) ? out.num : (-out.num); 01025 01026 return out; 01027 } 01028 01029 01030 /* ******************************************************************* 01031 * reduce a fraction by GCF elimination. This is NOT done as a 01032 * part of the arithmetic API unless GNC_HOW_DENOM_REDUCE is specified 01033 * as the output denominator. 01034 ********************************************************************/ 01035 01036 gnc_numeric 01037 gnc_numeric_reduce(gnc_numeric in) 01038 { 01039 gint64 t; 01040 gint64 num = (in.num < 0) ? (- in.num) : in.num ; 01041 gint64 denom = in.denom; 01042 gnc_numeric out; 01043 01044 if (gnc_numeric_check(in)) 01045 { 01046 return gnc_numeric_error(GNC_ERROR_ARG); 01047 } 01048 01049 /* The strategy is to use Euclid's algorithm */ 01050 while (denom > 0) 01051 { 01052 t = num % denom; 01053 num = denom; 01054 denom = t; 01055 } 01056 /* num now holds the GCD (Greatest Common Divisor) */ 01057 01058 /* All calculations are done on positive num, since it's not 01059 * well defined what % does for negative values */ 01060 out.num = in.num / num; 01061 out.denom = in.denom / num; 01062 return out; 01063 } 01064 01065 01066 /* ******************************************************************* 01067 * gnc_numeric_to_decimal 01068 * 01069 * Attempt to convert the denominator to an exact power of ten without 01070 * rounding. TRUE is returned if 'a' has been converted or was already 01071 * decimal. Otherwise, FALSE is returned and 'a' remains unchanged. 01072 * The 'max_decimal_places' parameter may be NULL. 01073 ********************************************************************/ 01074 01075 gboolean 01076 gnc_numeric_to_decimal(gnc_numeric *a, guint8 *max_decimal_places) 01077 { 01078 guint8 decimal_places = 0; 01079 gnc_numeric converted_val; 01080 gint64 fraction; 01081 01082 g_return_val_if_fail(a, FALSE); 01083 01084 if (gnc_numeric_check(*a) != GNC_ERROR_OK) 01085 return FALSE; 01086 01087 converted_val = *a; 01088 if (converted_val.denom <= 0) 01089 { 01090 converted_val = gnc_numeric_convert(converted_val, 1, GNC_HOW_DENOM_EXACT); 01091 if (gnc_numeric_check(converted_val) != GNC_ERROR_OK) 01092 return FALSE; 01093 *a = converted_val; 01094 if (max_decimal_places) 01095 *max_decimal_places = decimal_places; 01096 return TRUE; 01097 } 01098 01099 /* Zero is easily converted. */ 01100 if (converted_val.num == 0) 01101 converted_val.denom = 1; 01102 01103 fraction = converted_val.denom; 01104 while (fraction != 1) 01105 { 01106 switch (fraction % 10) 01107 { 01108 case 0: 01109 fraction = fraction / 10; 01110 break; 01111 01112 case 5: 01113 converted_val = gnc_numeric_mul(converted_val, 01114 gnc_numeric_create(2, 2), 01115 GNC_DENOM_AUTO, 01116 GNC_HOW_DENOM_EXACT | 01117 GNC_HOW_RND_NEVER); 01118 if (gnc_numeric_check(converted_val) != GNC_ERROR_OK) 01119 return FALSE; 01120 fraction = fraction / 5; 01121 break; 01122 01123 case 2: 01124 case 4: 01125 case 6: 01126 case 8: 01127 converted_val = gnc_numeric_mul(converted_val, 01128 gnc_numeric_create(5, 5), 01129 GNC_DENOM_AUTO, 01130 GNC_HOW_DENOM_EXACT | 01131 GNC_HOW_RND_NEVER); 01132 if (gnc_numeric_check(converted_val) != GNC_ERROR_OK) 01133 return FALSE; 01134 fraction = fraction / 2; 01135 break; 01136 01137 default: 01138 return FALSE; 01139 } 01140 01141 decimal_places += 1; 01142 } 01143 01144 if (max_decimal_places) 01145 *max_decimal_places = decimal_places; 01146 01147 *a = converted_val; 01148 01149 return TRUE; 01150 } 01151 01152 01153 /* ******************************************************************* 01154 * double_to_gnc_numeric 01155 ********************************************************************/ 01156 01157 #ifdef _MSC_VER 01158 # define rint /* */ 01159 #endif 01160 01161 gnc_numeric 01162 double_to_gnc_numeric(double in, gint64 denom, gint how) 01163 { 01164 gnc_numeric out; 01165 gint64 int_part = 0; 01166 double frac_part; 01167 gint64 frac_int = 0; 01168 double logval; 01169 double sigfigs; 01170 01171 if ((denom == GNC_DENOM_AUTO) && (how & GNC_HOW_DENOM_SIGFIG)) 01172 { 01173 if (fabs(in) < 10e-20) 01174 { 01175 logval = 0; 01176 } 01177 else 01178 { 01179 logval = log10(fabs(in)); 01180 logval = ((logval > 0.0) ? 01181 (floor(logval) + 1.0) : (ceil(logval))); 01182 } 01183 sigfigs = GNC_HOW_GET_SIGFIGS(how); 01184 if (sigfigs - logval >= 0) 01185 { 01186 denom = (gint64)(pow(10, sigfigs - logval)); 01187 } 01188 else 01189 { 01190 denom = -((gint64)(pow(10, logval - sigfigs))); 01191 } 01192 01193 how = how & ~GNC_HOW_DENOM_SIGFIG & ~GNC_NUMERIC_SIGFIGS_MASK; 01194 } 01195 01196 int_part = (gint64)(floor(fabs(in))); 01197 frac_part = in - (double)int_part; 01198 01199 int_part = int_part * denom; 01200 frac_part = frac_part * (double)denom; 01201 01202 switch (how & GNC_NUMERIC_RND_MASK) 01203 { 01204 case GNC_HOW_RND_FLOOR: 01205 frac_int = (gint64)floor(frac_part); 01206 break; 01207 01208 case GNC_HOW_RND_CEIL: 01209 frac_int = (gint64)ceil(frac_part); 01210 break; 01211 01212 case GNC_HOW_RND_TRUNC: 01213 frac_int = (gint64)frac_part; 01214 break; 01215 01216 case GNC_HOW_RND_ROUND: 01217 case GNC_HOW_RND_ROUND_HALF_UP: 01218 frac_int = (gint64)rint(frac_part); 01219 break; 01220 01221 case GNC_HOW_RND_NEVER: 01222 frac_int = (gint64)floor(frac_part); 01223 if (frac_part != (double) frac_int) 01224 { 01225 /* signal an error */ 01226 } 01227 break; 01228 } 01229 01230 out.num = int_part + frac_int; 01231 out.denom = denom; 01232 return out; 01233 } 01234 01235 /* ******************************************************************* 01236 * gnc_numeric_to_double 01237 ********************************************************************/ 01238 01239 double 01240 gnc_numeric_to_double(gnc_numeric in) 01241 { 01242 if (in.denom > 0) 01243 { 01244 return (double)in.num / (double)in.denom; 01245 } 01246 else 01247 { 01248 return (double)(in.num * -in.denom); 01249 } 01250 } 01251 01252 /* ******************************************************************* 01253 * gnc_numeric_error 01254 ********************************************************************/ 01255 01256 gnc_numeric 01257 gnc_numeric_error(GNCNumericErrorCode error_code) 01258 { 01259 return gnc_numeric_create(error_code, 0LL); 01260 } 01261 01262 01263 /* ******************************************************************* 01264 * gnc_numeric_add_with_error 01265 ********************************************************************/ 01266 01267 gnc_numeric 01268 gnc_numeric_add_with_error(gnc_numeric a, gnc_numeric b, 01269 gint64 denom, gint how, 01270 gnc_numeric * error) 01271 { 01272 01273 gnc_numeric sum = gnc_numeric_add(a, b, denom, how); 01274 gnc_numeric exact = gnc_numeric_add(a, b, GNC_DENOM_AUTO, 01275 GNC_HOW_DENOM_REDUCE); 01276 gnc_numeric err = gnc_numeric_sub(sum, exact, GNC_DENOM_AUTO, 01277 GNC_HOW_DENOM_REDUCE); 01278 01279 if (error) 01280 { 01281 *error = err; 01282 } 01283 return sum; 01284 } 01285 01286 /* ******************************************************************* 01287 * gnc_numeric_sub_with_error 01288 ********************************************************************/ 01289 01290 gnc_numeric 01291 gnc_numeric_sub_with_error(gnc_numeric a, gnc_numeric b, 01292 gint64 denom, gint how, 01293 gnc_numeric * error) 01294 { 01295 gnc_numeric diff = gnc_numeric_sub(a, b, denom, how); 01296 gnc_numeric exact = gnc_numeric_sub(a, b, GNC_DENOM_AUTO, 01297 GNC_HOW_DENOM_REDUCE); 01298 gnc_numeric err = gnc_numeric_sub(diff, exact, GNC_DENOM_AUTO, 01299 GNC_HOW_DENOM_REDUCE); 01300 if (error) 01301 { 01302 *error = err; 01303 } 01304 return diff; 01305 } 01306 01307 01308 /* ******************************************************************* 01309 * gnc_numeric_mul_with_error 01310 ********************************************************************/ 01311 01312 gnc_numeric 01313 gnc_numeric_mul_with_error(gnc_numeric a, gnc_numeric b, 01314 gint64 denom, gint how, 01315 gnc_numeric * error) 01316 { 01317 gnc_numeric prod = gnc_numeric_mul(a, b, denom, how); 01318 gnc_numeric exact = gnc_numeric_mul(a, b, GNC_DENOM_AUTO, 01319 GNC_HOW_DENOM_REDUCE); 01320 gnc_numeric err = gnc_numeric_sub(prod, exact, GNC_DENOM_AUTO, 01321 GNC_HOW_DENOM_REDUCE); 01322 if (error) 01323 { 01324 *error = err; 01325 } 01326 return prod; 01327 } 01328 01329 01330 /* ******************************************************************* 01331 * gnc_numeric_div_with_error 01332 ********************************************************************/ 01333 01334 gnc_numeric 01335 gnc_numeric_div_with_error(gnc_numeric a, gnc_numeric b, 01336 gint64 denom, gint how, 01337 gnc_numeric * error) 01338 { 01339 gnc_numeric quot = gnc_numeric_div(a, b, denom, how); 01340 gnc_numeric exact = gnc_numeric_div(a, b, GNC_DENOM_AUTO, 01341 GNC_HOW_DENOM_REDUCE); 01342 gnc_numeric err = gnc_numeric_sub(quot, exact, 01343 GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE); 01344 if (error) 01345 { 01346 *error = err; 01347 } 01348 return quot; 01349 } 01350 01351 /* ******************************************************************* 01352 * gnc_numeric text IO 01353 ********************************************************************/ 01354 01355 gchar * 01356 gnc_numeric_to_string(gnc_numeric n) 01357 { 01358 gchar *result; 01359 gint64 tmpnum = n.num; 01360 gint64 tmpdenom = n.denom; 01361 01362 result = g_strdup_printf("%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, tmpnum, tmpdenom); 01363 01364 return result; 01365 } 01366 01367 gchar * 01368 gnc_num_dbg_to_string(gnc_numeric n) 01369 { 01370 static char buff[1000]; 01371 static char *p = buff; 01372 gint64 tmpnum = n.num; 01373 gint64 tmpdenom = n.denom; 01374 01375 p += 100; 01376 if (p - buff >= 1000) p = buff; 01377 01378 sprintf(p, "%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, tmpnum, tmpdenom); 01379 01380 return p; 01381 } 01382 01383 gboolean 01384 string_to_gnc_numeric(const gchar* str, gnc_numeric *n) 01385 { 01386 gint64 tmpnum; 01387 gint64 tmpdenom; 01388 01389 if (!str) return FALSE; 01390 01391 tmpnum = g_ascii_strtoll (str, NULL, 0); 01392 str = strchr (str, '/'); 01393 if (!str) return FALSE; 01394 str ++; 01395 tmpdenom = g_ascii_strtoll (str, NULL, 0); 01396 01397 n->num = tmpnum; 01398 n->denom = tmpdenom; 01399 return TRUE; 01400 } 01401 01402 /* ******************************************************************* 01403 * GValue handling 01404 ********************************************************************/ 01405 static gpointer 01406 gnc_numeric_boxed_copy_func( gpointer in_gnc_numeric ) 01407 { 01408 gnc_numeric* newvalue; 01409 01410 newvalue = g_malloc( sizeof( gnc_numeric ) ); 01411 memcpy( newvalue, in_gnc_numeric, sizeof( gnc_numeric ) ); 01412 01413 return newvalue; 01414 } 01415 01416 static void 01417 gnc_numeric_boxed_free_func( gpointer in_gnc_numeric ) 01418 { 01419 g_free( in_gnc_numeric ); 01420 } 01421 01422 GType 01423 gnc_numeric_get_type( void ) 01424 { 01425 static GType type = 0; 01426 01427 if ( type == 0 ) 01428 { 01429 type = g_boxed_type_register_static( "gnc_numeric", 01430 gnc_numeric_boxed_copy_func, 01431 gnc_numeric_boxed_free_func ); 01432 } 01433 01434 return type; 01435 } 01436 01437 /* ******************************************************************* 01438 * gnc_numeric misc testing 01439 ********************************************************************/ 01440 #ifdef _GNC_NUMERIC_TEST 01441 01442 static char * 01443 gnc_numeric_print(gnc_numeric in) 01444 { 01445 char * retval; 01446 if (gnc_numeric_check(in)) 01447 { 01448 retval = g_strdup_printf("<ERROR> [%" G_GINT64_FORMAT " / %" G_GINT64_FORMAT "]", 01449 in.num, 01450 in.denom); 01451 } 01452 else 01453 { 01454 retval = g_strdup_printf("[%" G_GINT64_FORMAT " / %" G_GINT64_FORMAT "]", 01455 in.num, 01456 in.denom); 01457 } 01458 return retval; 01459 } 01460 01461 int 01462 main(int argc, char ** argv) 01463 { 01464 gnc_numeric a = gnc_numeric_create(1, 3); 01465 gnc_numeric b = gnc_numeric_create(1, 4); 01466 gnc_numeric c; 01467 01468 gnc_numeric err; 01469 01470 c = gnc_numeric_add_with_error(a, b, 100, GNC_HOW_RND_ROUND, &err); 01471 printf("add 100ths/error : %s + %s = %s + (error) %s\n\n", 01472 gnc_numeric_print(a), gnc_numeric_print(b), 01473 gnc_numeric_print(c), 01474 gnc_numeric_print(err)); 01475 01476 c = gnc_numeric_sub_with_error(a, b, 100, GNC_HOW_RND_FLOOR, &err); 01477 printf("sub 100ths/error : %s - %s = %s + (error) %s\n\n", 01478 gnc_numeric_print(a), gnc_numeric_print(b), 01479 gnc_numeric_print(c), 01480 gnc_numeric_print(err)); 01481 01482 c = gnc_numeric_mul_with_error(a, b, 100, GNC_HOW_RND_ROUND, &err); 01483 printf("mul 100ths/error : %s * %s = %s + (error) %s\n\n", 01484 gnc_numeric_print(a), gnc_numeric_print(b), 01485 gnc_numeric_print(c), 01486 gnc_numeric_print(err)); 01487 01488 c = gnc_numeric_div_with_error(a, b, 100, GNC_HOW_RND_ROUND, &err); 01489 printf("div 100ths/error : %s / %s = %s + (error) %s\n\n", 01490 gnc_numeric_print(a), gnc_numeric_print(b), 01491 gnc_numeric_print(c), 01492 gnc_numeric_print(err)); 01493 01494 printf("multiply (EXACT): %s * %s = %s\n", 01495 gnc_numeric_print(a), gnc_numeric_print(b), 01496 gnc_numeric_print(gnc_numeric_mul(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT))); 01497 01498 printf("multiply (REDUCE): %s * %s = %s\n", 01499 gnc_numeric_print(a), gnc_numeric_print(b), 01500 gnc_numeric_print(gnc_numeric_mul(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE))); 01501 01502 01503 return 0; 01504 } 01505 #endif 01506 01507 const char* gnc_numeric_errorCode_to_string(GNCNumericErrorCode error_code) 01508 { 01509 switch (error_code) 01510 { 01511 case GNC_ERROR_OK: 01512 return "GNC_ERROR_OK"; 01513 case GNC_ERROR_ARG: 01514 return "GNC_ERROR_ARG"; 01515 case GNC_ERROR_OVERFLOW: 01516 return "GNC_ERROR_OVERFLOW"; 01517 case GNC_ERROR_DENOM_DIFF: 01518 return "GNC_ERROR_DENOM_DIFF"; 01519 case GNC_ERROR_REMAINDER: 01520 return "GNC_ERROR_REMAINDER"; 01521 default: 01522 return "<unknown>"; 01523 } 01524 } 01525 01526 /* ======================== END OF FILE =================== */
1.7.4