QOF  0.8.7
qofnumeric.c
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 =================== */