GnuCash 2.4.99
gnc-numeric.c
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 =================== */
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines