gnc-numeric.h File Reference


Detailed Description

An exact-rational-number library for gnucash. (to be renamed qofnumeric.h in libqof2).

Author:
Copyright (C) 2000 Bill Gribble

Copyright (C) 2004 Linas Vepstas <linas@linas.org>

Definition in file gnc-numeric.h.

Go to the source code of this file.

Data Structures

struct  _gnc_numeric

Arguments Standard Arguments to most functions

Most of the gnc_numeric arithmetic functions take two arguments in addition to their numeric args: 'denom', which is the denominator to use in the output gnc_numeric object, and 'how'. which describes how the arithmetic result is to be converted to that denominator. This combination of output denominator and rounding policy allows the results of financial and other rational computations to be properly rounded to the appropriate units.

Valid values for denom are: GNC_DENOM_AUTO -- compute denominator exactly integer n -- Force the denominator of the result to be this integer GNC_DENOM_RECIPROCAL -- Use 1/n as the denominator (???huh???)

Valid values for 'how' are bitwise combinations of zero or one "rounding instructions" with zero or one "denominator types". Valid rounding instructions are: GNC_HOW_RND_FLOOR GNC_HOW_RND_CEIL GNC_HOW_RND_TRUNC GNC_HOW_RND_PROMOTE GNC_HOW_RND_ROUND_HALF_DOWN GNC_HOW_RND_ROUND_HALF_UP GNC_HOW_RND_ROUND GNC_HOW_RND_NEVER

The denominator type specifies how to compute a denominator if GNC_DENOM_AUTO is specified as the 'denom'. Valid denominator types are: GNC_HOW_DENOM_EXACT GNC_HOW_DENOM_REDUCE GNC_HOW_DENOM_LCD GNC_HOW_DENOM_FIXED GNC_HOW_DENOM_SIGFIGS(N)

To use traditional rational-number operational semantics (all results are exact and are reduced to relatively-prime fractions) pass the argument GNC_DENOM_AUTO as 'denom' and GNC_HOW_DENOM_REDUCE| GNC_HOW_RND_NEVER as 'how'.

To enforce strict financial semantics (such that all operands must have the same denominator as each other and as the result), use GNC_DENOM_AUTO as 'denom' and GNC_HOW_DENOM_FIXED | GNC_HOW_RND_NEVER as 'how'.

#define GNC_NUMERIC_RND_MASK   0x0000000f
 bitmasks for HOW flags.
#define GNC_NUMERIC_DENOM_MASK   0x000000f0
#define GNC_NUMERIC_SIGFIGS_MASK   0x0000ff00
#define GNC_HOW_DENOM_SIGFIGS(n)   ( ((( n ) & 0xff) << 8) | GNC_HOW_DENOM_SIGFIG)
#define GNC_HOW_GET_SIGFIGS(a)   ( (( a ) & 0xff00 ) >> 8)
#define GNC_DENOM_AUTO   0
#define GNC_DENOM_RECIPROCAL(a)   (- ( a ))
enum  {
  GNC_HOW_RND_FLOOR = 0x01, GNC_HOW_RND_CEIL = 0x02, GNC_HOW_RND_TRUNC = 0x03, GNC_HOW_RND_PROMOTE = 0x04,
  GNC_HOW_RND_ROUND_HALF_DOWN = 0x05, GNC_HOW_RND_ROUND_HALF_UP = 0x06, GNC_HOW_RND_ROUND = 0x07, GNC_HOW_RND_NEVER = 0x08
}
 Rounding/Truncation modes for operations. More...
enum  {
  GNC_HOW_DENOM_EXACT = 0x10, GNC_HOW_DENOM_REDUCE = 0x20, GNC_HOW_DENOM_LCD = 0x30, GNC_HOW_DENOM_FIXED = 0x40,
  GNC_HOW_DENOM_SIGFIG = 0x50
}
enum  GNCNumericErrorCode {
  GNC_ERROR_OK = 0, GNC_ERROR_ARG = -1, GNC_ERROR_OVERFLOW = -2, GNC_ERROR_DENOM_DIFF = -3,
  GNC_ERROR_REMAINDER = -4
}

Deprecated, backwards-compatible definitions

#define GNC_RND_FLOOR   GNC_HOW_RND_FLOOR
#define GNC_RND_CEIL   GNC_HOW_RND_CEIL
#define GNC_RND_TRUNC   GNC_HOW_RND_TRUNC
#define GNC_RND_PROMOTE   GNC_HOW_RND_PROMOTE
#define GNC_RND_ROUND_HALF_DOWN   GNC_HOW_RND_ROUND_HALF_DOWN
#define GNC_RND_ROUND_HALF_UP   GNC_HOW_RND_ROUND_HALF_UP
#define GNC_RND_ROUND   GNC_HOW_RND_ROUND
#define GNC_RND_NEVER   GNC_HOW_RND_NEVER
#define GNC_DENOM_EXACT   GNC_HOW_DENOM_EXACT
#define GNC_DENOM_REDUCE   GNC_HOW_DENOM_REDUCE
#define GNC_DENOM_LCD   GNC_HOW_DENOM_LCD
#define GNC_DENOM_FIXED   GNC_HOW_DENOM_FIXED
#define GNC_DENOM_SIGFIG   GNC_HOW_DENOM_SIGFIG
#define GNC_DENOM_SIGFIGS(X)   GNC_HOW_DENOM_SIGFIGS(X)
#define GNC_NUMERIC_GET_SIGFIGS(X)   GNC_HOW_GET_SIGFIGS(X)

Constructors

static gnc_numeric gnc_numeric_create (gint64 num, gint64 denom)
static gnc_numeric gnc_numeric_zero (void)
gnc_numeric double_to_gnc_numeric (double in, gint64 denom, gint how)
gboolean string_to_gnc_numeric (const gchar *str, gnc_numeric *n)
gnc_numeric gnc_numeric_error (GNCNumericErrorCode error_code)

Value Accessors

static gint64 gnc_numeric_num (gnc_numeric a)
static gint64 gnc_numeric_denom (gnc_numeric a)
gdouble gnc_numeric_to_double (gnc_numeric in)
gchar * gnc_numeric_to_string (gnc_numeric n)
gchar * gnc_num_dbg_to_string (gnc_numeric n)

Comparisons and Predicates

GNCNumericErrorCode gnc_numeric_check (gnc_numeric a)
gint gnc_numeric_compare (gnc_numeric a, gnc_numeric b)
gboolean gnc_numeric_zero_p (gnc_numeric a)
gboolean gnc_numeric_negative_p (gnc_numeric a)
gboolean gnc_numeric_positive_p (gnc_numeric a)
gboolean gnc_numeric_eq (gnc_numeric a, gnc_numeric b)
gboolean gnc_numeric_equal (gnc_numeric a, gnc_numeric b)
gint gnc_numeric_same (gnc_numeric a, gnc_numeric b, gint64 denom, gint how)

Arithmetic Operations

gnc_numeric gnc_numeric_add (gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
gnc_numeric gnc_numeric_sub (gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
gnc_numeric gnc_numeric_mul (gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
gnc_numeric gnc_numeric_div (gnc_numeric x, gnc_numeric y, gint64 denom, gint how)
gnc_numeric gnc_numeric_neg (gnc_numeric a)
gnc_numeric gnc_numeric_abs (gnc_numeric a)
static gnc_numeric gnc_numeric_add_fixed (gnc_numeric a, gnc_numeric b)
static gnc_numeric gnc_numeric_sub_fixed (gnc_numeric a, gnc_numeric b)

Arithmetic Functions with Exact Error Returns

gnc_numeric gnc_numeric_add_with_error (gnc_numeric a, gnc_numeric b, gint64 denom, gint how, gnc_numeric *error)
gnc_numeric gnc_numeric_sub_with_error (gnc_numeric a, gnc_numeric b, gint64 denom, gint how, gnc_numeric *error)
gnc_numeric gnc_numeric_mul_with_error (gnc_numeric a, gnc_numeric b, gint64 denom, gint how, gnc_numeric *error)
gnc_numeric gnc_numeric_div_with_error (gnc_numeric a, gnc_numeric b, gint64 denom, gint how, gnc_numeric *error)

Change Denominator

gnc_numeric gnc_numeric_convert (gnc_numeric in, gint64 denom, gint how)
gnc_numeric gnc_numeric_convert_with_error (gnc_numeric in, gint64 denom, gint how, gnc_numeric *error)
gnc_numeric gnc_numeric_reduce (gnc_numeric in)

Typedefs

typedef _gnc_numeric gnc_numeric
 An rational-number type.


Define Documentation

#define GNC_DENOM_AUTO   0
 

Compute an appropriate denominator automatically. Flags in the 'how' argument will specify how to compute the denominator.

Definition at line 229 of file gnc-numeric.h.

#define GNC_DENOM_RECIPROCAL  )     (- ( a ))
 

Use the value 1/n as the denominator of the output value.

Definition at line 232 of file gnc-numeric.h.

#define GNC_HOW_DENOM_SIGFIGS  )     ( ((( n ) & 0xff) << 8) | GNC_HOW_DENOM_SIGFIG)
 

Build a 'how' value that will generate a denominator that will keep at least n significant figures in the result.

Definition at line 202 of file gnc-numeric.h.

#define GNC_NUMERIC_RND_MASK   0x0000000f
 

bitmasks for HOW flags.

bits 8-15 of 'how' are reserved for the number of significant digits to use in the output with GNC_HOW_DENOM_SIGFIG

Definition at line 117 of file gnc-numeric.h.


Enumeration Type Documentation

anonymous enum
 

Rounding/Truncation modes for operations.

Rounding instructions control how fractional parts in the specified denominator affect the result. For example, if a computed result is "3/4" but the specified denominator for the return value is 2, should the return value be "1/2" or "2/2"?

Possible rounding instructions are:

Enumerator:
GNC_HOW_RND_FLOOR  Round toward -infinity
GNC_HOW_RND_CEIL  Round toward +infinity
GNC_HOW_RND_TRUNC  Truncate fractions (round toward zero)
GNC_HOW_RND_PROMOTE  Promote fractions (round away from zero)
GNC_HOW_RND_ROUND_HALF_DOWN  Round to the nearest integer, rounding toward zero when there are two equidistant nearest integers.
GNC_HOW_RND_ROUND_HALF_UP  Round to the nearest integer, rounding away from zero when there are two equidistant nearest integers.
GNC_HOW_RND_ROUND  Use unbiased ("banker's") rounding. This rounds to the nearest integer, and to the nearest even integer when there are two equidistant nearest integers. This is generally the one you should use for financial quantities.
GNC_HOW_RND_NEVER  Never round at all, and signal an error if there is a fractional result in a computation.

Definition at line 130 of file gnc-numeric.h.

00130      { 
00132   GNC_HOW_RND_FLOOR            = 0x01, 
00133 
00135   GNC_HOW_RND_CEIL             = 0x02,  
00136 
00138   GNC_HOW_RND_TRUNC            = 0x03,
00139 
00141   GNC_HOW_RND_PROMOTE          = 0x04,
00142 
00146   GNC_HOW_RND_ROUND_HALF_DOWN  = 0x05, 
00147 
00151   GNC_HOW_RND_ROUND_HALF_UP    = 0x06, 
00152 
00158   GNC_HOW_RND_ROUND            = 0x07, 
00159 
00163   GNC_HOW_RND_NEVER            = 0x08
00164 };

anonymous enum
 

How to compute a denominator, or'ed into the "how" field.

Enumerator:
GNC_HOW_DENOM_EXACT  Use any denominator which gives an exactly correct ratio of numerator to denominator. Use EXACT when you do not wish to lose any information in the result but also do not want to spend any time finding the "best" denominator.
GNC_HOW_DENOM_REDUCE  Reduce the result value by common factor elimination, using the smallest possible value for the denominator that keeps the correct ratio. The numerator and denominator of the result are relatively prime.
GNC_HOW_DENOM_LCD  Find the least common multiple of the arguments' denominators and use that as the denominator of the result.
GNC_HOW_DENOM_FIXED  All arguments are required to have the same denominator, that denominator is to be used in the output, and an error is to be signaled if any argument has a different denominator.
GNC_HOW_DENOM_SIGFIG  Round to the number of significant figures given in the rounding instructions by the GNC_HOW_DENOM_SIGFIGS () macro.

Definition at line 167 of file gnc-numeric.h.

00167      { 
00173   GNC_HOW_DENOM_EXACT  = 0x10, 
00174 
00180   GNC_HOW_DENOM_REDUCE = 0x20,
00181 
00185   GNC_HOW_DENOM_LCD    = 0x30,
00186 
00191   GNC_HOW_DENOM_FIXED  = 0x40,
00192 
00196   GNC_HOW_DENOM_SIGFIG = 0x50
00197 };

enum GNCNumericErrorCode
 

Error codes

Enumerator:
GNC_ERROR_OK  No error
GNC_ERROR_ARG  Argument is not a valid number
GNC_ERROR_OVERFLOW  Intermediate result overflow
GNC_ERROR_DENOM_DIFF  GNC_HOW_DENOM_FIXED was specified, but argument denominators differed.
GNC_ERROR_REMAINDER  GNC_HOW_RND_NEVER was specified, but the result could not be converted to the desired denominator without a remainder.

Definition at line 206 of file gnc-numeric.h.

00206              {
00207   GNC_ERROR_OK         =  0,   
00208   GNC_ERROR_ARG        = -1,   
00209   GNC_ERROR_OVERFLOW   = -2,   
00212   GNC_ERROR_DENOM_DIFF = -3,   
00213 
00216   GNC_ERROR_REMAINDER  = -4   
00217 } GNCNumericErrorCode;


Function Documentation

gnc_numeric double_to_gnc_numeric double  in,
gint64  denom,
gint  how
 

Convert a floating-point number to a gnc_numeric. Both 'denom' and 'how' are used as in arithmetic, but GNC_DENOM_AUTO is not recognized; a denominator must be specified either explicitctly or through sigfigs.

Definition at line 1023 of file gnc-numeric.c.

01024 {
01025   gnc_numeric out;
01026   gint64 int_part=0;
01027   double frac_part;
01028   gint64 frac_int=0;
01029   double logval; 
01030   double sigfigs;
01031 
01032   if((denom == GNC_DENOM_AUTO) && (how & GNC_HOW_DENOM_SIGFIG)) 
01033   {
01034     if(fabs(in) < 10e-20) {
01035       logval = 0;
01036     }
01037     else {
01038       logval   = log10(fabs(in));
01039       logval   = ((logval > 0.0) ? 
01040                   (floor(logval)+1.0) : (ceil(logval)));
01041     }
01042     sigfigs  = GNC_HOW_GET_SIGFIGS(how);
01043     if(sigfigs-logval >= 0) {
01044       denom    = (gint64)(pow(10, sigfigs-logval));
01045     }
01046     else {
01047       denom    = -((gint64)(pow(10, logval-sigfigs)));
01048     }
01049 
01050     how =  how & ~GNC_HOW_DENOM_SIGFIG & ~GNC_NUMERIC_SIGFIGS_MASK;
01051   }
01052 
01053   int_part  = (gint64)(floor(fabs(in)));
01054   frac_part = in - (double)int_part;
01055   
01056   int_part = int_part * denom;
01057   frac_part = frac_part * (double)denom;
01058 
01059   switch(how & GNC_NUMERIC_RND_MASK) {
01060   case GNC_HOW_RND_FLOOR:
01061     frac_int = (gint64)floor(frac_part);
01062     break;
01063 
01064   case GNC_HOW_RND_CEIL:
01065     frac_int = (gint64)ceil(frac_part);
01066     break;
01067 
01068   case GNC_HOW_RND_TRUNC:
01069     frac_int = (gint64)frac_part;
01070     break;
01071     
01072   case GNC_HOW_RND_ROUND:
01073   case GNC_HOW_RND_ROUND_HALF_UP:
01074     frac_int = (gint64)rint(frac_part);
01075     break;
01076 
01077   case GNC_HOW_RND_NEVER:
01078     frac_int = (gint64)floor(frac_part);
01079     if(frac_part != (double) frac_int) {
01080       /* signal an error */
01081     }
01082     break;
01083   }
01084 
01085   out.num   = int_part + frac_int; 
01086   out.denom = denom;
01087   return out;
01088 }

gchar* gnc_num_dbg_to_string gnc_numeric  n  ) 
 

Convert to string. Uses a static, non-thread-safe buffer. For internal use only.

Definition at line 1219 of file gnc-numeric.c.

01220 {
01221   static char buff[1000];
01222   static char *p = buff;
01223   gint64 tmpnum = n.num;
01224   gint64 tmpdenom = n.denom;
01225 
01226   p+= 100;
01227   if (p-buff >= 1000) p = buff;
01228    
01229   sprintf(p, "%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, tmpnum, tmpdenom);
01230 
01231   return p;
01232 }

gnc_numeric gnc_numeric_abs gnc_numeric  a  ) 
 

Return the absolute value of the argument

Definition at line 721 of file gnc-numeric.c.

00722 {
00723   if(gnc_numeric_check(a)) {
00724     return gnc_numeric_error(GNC_ERROR_ARG);
00725   }
00726   return gnc_numeric_create(ABS(a.num), a.denom);
00727 }

gnc_numeric gnc_numeric_add gnc_numeric  a,
gnc_numeric  b,
gint64  denom,
gint  how
 

Return a+b.

Definition at line 346 of file gnc-numeric.c.

00348 {
00349   gnc_numeric sum;
00350   
00351   if(gnc_numeric_check(a) || gnc_numeric_check(b)) 
00352   {
00353     return gnc_numeric_error(GNC_ERROR_ARG);
00354   }
00355 
00356   if((denom == GNC_DENOM_AUTO) && 
00357      (how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_FIXED) 
00358   {
00359     if(a.denom == b.denom) {
00360       denom = a.denom;
00361     }
00362     else if(b.num == 0) {
00363       denom = a.denom;
00364       b.denom = a.denom;
00365     }
00366     else if(a.num == 0) {
00367       denom = b.denom;
00368       a.denom = b.denom;
00369     }
00370     else {
00371       return gnc_numeric_error(GNC_ERROR_DENOM_DIFF);
00372     }
00373   }
00374   
00375   if(a.denom < 0) 
00376   {
00377     a.num *= -a.denom;  /* BUG: overflow not handled.  */
00378     a.denom = 1;
00379   }
00380 
00381   if(b.denom < 0) 
00382   {
00383     b.num *= -b.denom;  /* BUG: overflow not handled.  */
00384     b.denom = 1;
00385   }
00386 
00387   /* Get an exact answer.. same denominator is the common case. */ 
00388   if(a.denom == b.denom) 
00389   {
00390     sum.num = a.num + b.num;  /* BUG: overflow not handled.  */
00391     sum.denom = a.denom;
00392   }
00393   else 
00394   {
00395     /* We want to do this:
00396      *    sum.num = a.num*b.denom + b.num*a.denom;
00397      *    sum.denom = a.denom*b.denom;
00398      * but the multiply could overflow.  
00399      * Computing the LCD minimizes likelihood of overflow
00400      */
00401     gint64 lcd;
00402     qofint128 ca, cb, cab;
00403     lcd = gnc_numeric_lcd(a,b);
00404     if (GNC_ERROR_ARG == lcd)
00405     {
00406        return gnc_numeric_error(GNC_ERROR_OVERFLOW);
00407     }
00408     ca = mult128 (a.num, lcd/a.denom);
00409     if (ca.isbig) return gnc_numeric_error(GNC_ERROR_OVERFLOW);
00410 
00411     cb = mult128 (b.num, lcd/b.denom);
00412     if (cb.isbig) return gnc_numeric_error(GNC_ERROR_OVERFLOW);
00413 
00414     cab = add128 (ca, cb);
00415     if (cab.isbig) return gnc_numeric_error(GNC_ERROR_OVERFLOW);
00416     
00417     sum.num   = cab.lo;
00418     if (cab.isneg) sum.num = -sum.num;
00419     sum.denom = lcd;
00420   }
00421   
00422   if((denom == GNC_DENOM_AUTO) &&
00423      ((how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_LCD)) 
00424   {
00425     denom = gnc_numeric_lcd(a, b);
00426     how   = how & GNC_NUMERIC_RND_MASK;
00427   }
00428   
00429   return gnc_numeric_convert(sum, denom, how);                             
00430 }

static gnc_numeric gnc_numeric_add_fixed gnc_numeric  a,
gnc_numeric  b
[inline, static]
 

Shortcut for common case: gnc_numeric_add(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_FIXED | GNC_HOW_RND_NEVER);

Definition at line 380 of file gnc-numeric.h.

00380                                                                 {
00381    return gnc_numeric_add(a, b, GNC_DENOM_AUTO,
00382                          GNC_HOW_DENOM_FIXED | GNC_HOW_RND_NEVER);
00383 }

gnc_numeric gnc_numeric_add_with_error gnc_numeric  a,
gnc_numeric  b,
gint64  denom,
gint  how,
gnc_numeric error
 

The same as gnc_numeric_add, but uses 'error' for accumulating conversion roundoff error.

Definition at line 1123 of file gnc-numeric.c.

01126 {
01127 
01128   gnc_numeric sum   = gnc_numeric_add(a, b, denom, how);
01129   gnc_numeric exact = gnc_numeric_add(a, b, GNC_DENOM_AUTO, 
01130                                       GNC_HOW_DENOM_REDUCE);
01131   gnc_numeric err   = gnc_numeric_sub(sum, exact, GNC_DENOM_AUTO,
01132                                       GNC_HOW_DENOM_REDUCE);
01133 
01134   if(error) {
01135     *error = err;
01136   }
01137   return sum;
01138 }

GNCNumericErrorCode gnc_numeric_check gnc_numeric  a  )  [inline]
 

Check for error signal in value. Returns GNC_ERROR_OK (==0) if the number appears to be valid, otherwise it returns the type of error. Error values always have a denominator of zero.

Definition at line 58 of file gnc-numeric.c.

00059 {
00060   if(in.denom != 0) 
00061   {
00062     return GNC_ERROR_OK;
00063   }
00064   else if(in.num) 
00065   {
00066     if ((0 < in.num) || (-4 > in.num))
00067     {
00068        in.num = (gint64) GNC_ERROR_OVERFLOW;
00069     }
00070     return (GNCNumericErrorCode) in.num;
00071   }
00072   else 
00073   {
00074     return GNC_ERROR_ARG;
00075   }
00076 }

gint gnc_numeric_compare gnc_numeric  a,
gnc_numeric  b
 

Returns 1 if a>b, -1 if b>a, 0 if a == b

Definition at line 221 of file gnc-numeric.c.

00222 {
00223   gint64 aa, bb;
00224   qofint128 l, r;
00225 
00226   if(gnc_numeric_check(a) || gnc_numeric_check(b)) 
00227   {
00228     return 0;
00229   }
00230 
00231   if (a.denom == b.denom)
00232   {
00233     if(a.num == b.num) return 0;
00234     if(a.num > b.num) return 1;
00235     return -1;
00236   }
00237 
00238   if  ((a.denom > 0) && (b.denom > 0))
00239   {
00240     /* Avoid overflows using 128-bit intermediate math */
00241     l = mult128 (a.num, b.denom);
00242     r = mult128 (b.num, a.denom);
00243     return cmp128 (l,r);
00244   }
00245 
00246   if (a.denom < 0)
00247       a.denom *= -1;
00248   if (b.denom < 0)
00249       b.denom *= -1;
00250 
00251   /* BUG: Possible overflow here..  Also, doesn't properly deal with
00252    * reciprocal denominators.
00253    */
00254   aa = a.num * a.denom;
00255   bb = b.num * b.denom;
00256 
00257   if(aa == bb) return 0;
00258   if(aa > bb) return 1;
00259   return -1;
00260 }

gnc_numeric gnc_numeric_convert gnc_numeric  in,
gint64  denom,
gint  how
 

Change the denominator of a gnc_numeric value to the specified denominator under standard arguments 'denom' and 'how'.

Definition at line 734 of file gnc-numeric.c.

00735 {
00736   gnc_numeric out;
00737   gnc_numeric temp;
00738   gint64      temp_bc;
00739   gint64      temp_a;
00740   gint64      remainder;  
00741   gint64      sign;
00742   gint        denom_neg=0;
00743   double      ratio, logratio;
00744   double      sigfigs;
00745   qofint128 nume, newm;
00746 
00747   temp.num   = 0;
00748   temp.denom = 0;
00749 
00750   if(gnc_numeric_check(in)) {
00751     return gnc_numeric_error(GNC_ERROR_ARG);
00752   }
00753   
00754   if(denom == GNC_DENOM_AUTO) 
00755   {
00756     switch(how & GNC_NUMERIC_DENOM_MASK) 
00757     {
00758     default:
00759     case GNC_HOW_DENOM_LCD:   /* LCD is meaningless with AUTO in here */
00760     case GNC_HOW_DENOM_EXACT:
00761       return in;
00762       break;
00763       
00764     case GNC_HOW_DENOM_REDUCE:
00765       /* reduce the input to a relatively-prime fraction */
00766       return gnc_numeric_reduce(in);
00767       break;
00768       
00769     case GNC_HOW_DENOM_FIXED:
00770       if(in.denom != denom) {
00771         return gnc_numeric_error(GNC_ERROR_DENOM_DIFF);
00772       }
00773       else {
00774         return in;
00775       }
00776       break;
00777       
00778     case GNC_HOW_DENOM_SIGFIG:
00779       ratio    = fabs(gnc_numeric_to_double(in));
00780       if(ratio < 10e-20) {
00781         logratio = 0;
00782       }
00783       else {
00784         logratio = log10(ratio);
00785         logratio = ((logratio > 0.0) ? 
00786                     (floor(logratio)+1.0) : (ceil(logratio)));
00787       }
00788       sigfigs  = GNC_HOW_GET_SIGFIGS(how);
00789 
00790       if(sigfigs-logratio >= 0) {
00791         denom    = (gint64)(pow(10, sigfigs-logratio));
00792       }
00793       else {
00794         denom    = -((gint64)(pow(10, logratio-sigfigs)));
00795       }
00796       
00797       how = how & ~GNC_HOW_DENOM_SIGFIG & ~GNC_NUMERIC_SIGFIGS_MASK;
00798       break;
00799 
00800     }
00801   }
00802   
00803   /* Make sure we need to do the work */
00804   if(in.denom == denom) {
00805     return in;
00806   }
00807   if(in.num == 0) {
00808     out.num = 0;
00809     out.denom = denom;
00810     return out;
00811   }
00812   
00813   /* If the denominator of the input value is negative, get rid of that. */
00814   if(in.denom < 0) {
00815     in.num = in.num * (- in.denom);  /* BUG: overflow not handled.  */
00816     in.denom = 1;
00817   }
00818   
00819   sign = (in.num < 0) ? -1 : 1;
00820 
00821   /* If the denominator is less than zero, we are to interpret it as 
00822    * the reciprocal of its magnitude. */
00823   if(denom < 0) 
00824   {
00825 
00826     /* XXX FIXME: use 128-bit math here ... */
00827     denom     = - denom;
00828     denom_neg = 1;
00829     temp_a    = (in.num < 0) ? -in.num : in.num;
00830     temp_bc   = in.denom * denom;  /* BUG: overflow not handled.  */
00831     remainder = temp_a % temp_bc;
00832     out.num   = temp_a / temp_bc;
00833     out.denom = - denom;    
00834   }
00835   else 
00836   {
00837     /* Do all the modulo and int division on positive values to make
00838      * things a little clearer. Reduce the fraction denom/in.denom to
00839      * help with range errors */
00840     temp.num   = denom;
00841     temp.denom = in.denom;
00842     temp       = gnc_numeric_reduce(temp);
00843 
00844     /* Symbolically, do the following:
00845      * out.num   = in.num * temp.num;
00846      * remainder = out.num % temp.denom;
00847      * out.num   = out.num / temp.denom;
00848      * out.denom = denom;
00849      */
00850     nume = mult128 (in.num, temp.num);
00851     newm = div128 (nume, temp.denom);
00852     remainder = rem128 (nume, temp.denom);
00853 
00854     if (newm.isbig)
00855     {
00856        return gnc_numeric_error(GNC_ERROR_OVERFLOW);
00857     }
00858 
00859     out.num = newm.lo;
00860     out.denom = denom;
00861   }
00862 
00863   if (remainder) 
00864   {
00865     switch(how & GNC_NUMERIC_RND_MASK) 
00866     {
00867     case GNC_HOW_RND_FLOOR:
00868       if(sign < 0) {
00869         out.num = out.num + 1;
00870       }
00871       break;
00872       
00873     case GNC_HOW_RND_CEIL:
00874       if(sign > 0) {
00875         out.num = out.num + 1;
00876       }
00877       break;
00878       
00879     case GNC_HOW_RND_TRUNC:
00880       break;
00881 
00882     case GNC_HOW_RND_PROMOTE:
00883       out.num = out.num + 1;
00884       break;
00885       
00886     case GNC_HOW_RND_ROUND_HALF_DOWN:
00887       if(denom_neg) 
00888       {
00889         if((2 * remainder) > in.denom*denom) 
00890         {
00891           out.num = out.num + 1;
00892         }
00893       }
00894       else if((2 * remainder) > temp.denom) 
00895       {
00896         out.num = out.num + 1;
00897       }
00898       /* check that 2*remainder didn't over-flow */
00899       else if (((2 * remainder) < remainder) && 
00900                (remainder > (temp.denom / 2)))
00901       {
00902         out.num = out.num + 1;
00903       }
00904       break;
00905       
00906     case GNC_HOW_RND_ROUND_HALF_UP:
00907       if(denom_neg) 
00908       {
00909         if((2 * remainder) >= in.denom*denom) 
00910         {
00911           out.num = out.num + 1;
00912         }
00913       }
00914       else if((2 * remainder ) >= temp.denom) 
00915       {
00916         out.num = out.num + 1;
00917       }
00918       /* check that 2*remainder didn't over-flow */
00919       else if (((2 * remainder) < remainder) && 
00920                (remainder >= (temp.denom / 2)))
00921       {
00922         out.num = out.num + 1;
00923       }
00924       break;
00925       
00926     case GNC_HOW_RND_ROUND:
00927       if(denom_neg) 
00928       {
00929         if((2 * remainder) > in.denom*denom) 
00930         {
00931           out.num = out.num + 1;
00932         }
00933         else if((2 * remainder) == in.denom*denom) 
00934         {
00935           if(out.num % 2) 
00936           {
00937             out.num = out.num + 1;
00938           }
00939         }        
00940       }
00941       else 
00942       {
00943         if((2 * remainder ) > temp.denom) 
00944         {
00945           out.num = out.num + 1;
00946         }
00947         /* check that 2*remainder didn't over-flow */
00948         else if (((2 * remainder) < remainder) && 
00949                  (remainder > (temp.denom / 2)))
00950         {
00951           out.num = out.num + 1;
00952         }
00953         else if((2 * remainder) == temp.denom) 
00954         {
00955           if(out.num % 2) 
00956           {
00957             out.num = out.num + 1;
00958           }
00959         }    
00960         /* check that 2*remainder didn't over-flow */
00961         else if (((2 * remainder) < remainder) && 
00962                  (remainder ==  (temp.denom / 2)))
00963         {
00964           if(out.num % 2) 
00965           {
00966             out.num = out.num + 1;
00967           }
00968         }
00969       }    
00970       break;
00971       
00972     case GNC_HOW_RND_NEVER:
00973       return gnc_numeric_error(GNC_ERROR_REMAINDER);
00974       break;
00975     }
00976   }
00977   
00978   out.num = (sign > 0) ? out.num : (-out.num);
00979   
00980   return out;
00981 }

gnc_numeric gnc_numeric_convert_with_error gnc_numeric  in,
gint64  denom,
gint  how,
gnc_numeric error
 

Same as gnc_numeric_convert, but return a remainder value for accumulating conversion error.

static gnc_numeric gnc_numeric_create gint64  num,
gint64  denom
[inline, static]
 

Make a gnc_numeric from numerator and denominator

Definition at line 241 of file gnc-numeric.h.

00241                                                          {
00242   gnc_numeric out;
00243   out.num = num;
00244   out.denom = denom;
00245   return out;
00246 }

static gint64 gnc_numeric_denom gnc_numeric  a  )  [inline, static]
 

Return denominator

Definition at line 279 of file gnc-numeric.h.

00279 { return a.denom; }

gnc_numeric gnc_numeric_div gnc_numeric  x,
gnc_numeric  y,
gint64  denom,
gint  how
 

Division. Note that division can overflow, in the following sense: if we write x=a/b and y=c/d then x/y = (a*d)/(b*c) If, after eliminating all common factors between the numerator (a*d) and the denominator (b*c), then if either the numerator and/or the denominator are *still* greater than 2^63, then the division has overflowed.

Definition at line 575 of file gnc-numeric.c.

00577 {
00578   gnc_numeric quotient;
00579   qofint128 nume, deno;
00580 
00581   if(gnc_numeric_check(a) || gnc_numeric_check(b)) 
00582   {
00583     return gnc_numeric_error(GNC_ERROR_ARG);
00584   }
00585 
00586   if((denom == GNC_DENOM_AUTO) && 
00587      (how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_FIXED) 
00588   {
00589     if(a.denom == b.denom) 
00590     {
00591       denom = a.denom;
00592     }
00593     else if(a.denom == 0) 
00594     {
00595       denom = b.denom;
00596     }
00597     else 
00598     {
00599       return gnc_numeric_error(GNC_ERROR_DENOM_DIFF);
00600     }
00601   }
00602   
00603 
00604   if(a.denom < 0) 
00605   {
00606     a.num *= -a.denom;   /* BUG: overflow not handled.  */
00607     a.denom = 1;
00608   }
00609 
00610   if(b.denom < 0) 
00611   {
00612     b.num *= -b.denom;   /* BUG: overflow not handled.  */
00613     b.denom = 1;
00614   }
00615 
00616   if(a.denom == b.denom) 
00617   {
00618     quotient.num = a.num;
00619     quotient.denom = b.num;
00620   }
00621   else 
00622   {
00623     gint64 sgn = 1;
00624     if (0 > a.num)
00625     {
00626       sgn = -sgn;
00627       a.num = -a.num;
00628     }
00629     if (0 > b.num)
00630     {
00631       sgn = -sgn;
00632       b.num = -b.num;
00633     }
00634     nume = mult128(a.num, b.denom);
00635     deno = mult128(b.num, a.denom);
00636 
00637     /* Try to avoid overflow by removing common factors */
00638     if (nume.isbig && deno.isbig)
00639     {
00640       gnc_numeric ra = gnc_numeric_reduce (a);
00641       gnc_numeric rb = gnc_numeric_reduce (b);
00642 
00643       gint64 gcf_nume = gcf64(ra.num, rb.num);
00644       gint64 gcf_deno = gcf64(rb.denom, ra.denom);
00645       nume = mult128(ra.num/gcf_nume, rb.denom/gcf_deno);
00646       deno = mult128(rb.num/gcf_nume, ra.denom/gcf_deno);
00647     }
00648 
00649     if ((0 == nume.isbig) && (0 == deno.isbig))
00650     {
00651       quotient.num = sgn * nume.lo;
00652       quotient.denom = deno.lo;
00653       goto dive_done;
00654     }
00655     else if (0 == deno.isbig)
00656     {
00657       quotient = reduce128 (nume, deno.lo);
00658       if (0 == gnc_numeric_check (quotient))
00659       {
00660         quotient.num *= sgn;
00661         goto dive_done;
00662       }
00663     }
00664 
00665     /* If rounding allowed, then shift until there's no 
00666      * more overflow. The conversion at the end will fix 
00667      * things up for the final value. */
00668     if ((how & GNC_NUMERIC_RND_MASK) == GNC_HOW_RND_NEVER)
00669     {
00670       return gnc_numeric_error (GNC_ERROR_OVERFLOW);
00671     }
00672     while (nume.isbig || deno.isbig)
00673     {
00674        nume = shift128 (nume);
00675        deno = shift128 (deno);
00676     }
00677     quotient.num = sgn * nume.lo;
00678     quotient.denom = deno.lo;
00679     if (0 == quotient.denom) 
00680     {
00681       return gnc_numeric_error (GNC_ERROR_OVERFLOW);
00682     }
00683   }
00684   
00685   if(quotient.denom < 0) 
00686   {
00687     quotient.num   = -quotient.num;
00688     quotient.denom = -quotient.denom;
00689   }
00690   
00691 dive_done:
00692   if((denom == GNC_DENOM_AUTO) &&
00693      ((how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_LCD)) 
00694   {
00695     denom = gnc_numeric_lcd(a, b);
00696     how   = how & GNC_NUMERIC_RND_MASK;
00697   }
00698 
00699   return gnc_numeric_convert(quotient, denom, how); 
00700 }

gnc_numeric gnc_numeric_div_with_error gnc_numeric  a,
gnc_numeric  b,
gint64  denom,
gint  how,
gnc_numeric error
 

The same as gnc_numeric_div, but uses error for accumulating conversion roundoff error.

Definition at line 1187 of file gnc-numeric.c.

01190 {
01191   gnc_numeric quot  = gnc_numeric_div(a, b, denom, how);
01192   gnc_numeric exact = gnc_numeric_div(a, b, GNC_DENOM_AUTO, 
01193                                       GNC_HOW_DENOM_REDUCE);
01194   gnc_numeric err   = gnc_numeric_sub(quot, exact, 
01195                                       GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
01196   if(error) {
01197     *error = err;
01198   }
01199   return quot;
01200 }

gboolean gnc_numeric_eq gnc_numeric  a,
gnc_numeric  b
 

Equivalence predicate: Returns TRUE (1) if a and b are exactly the same (have the same numerator and denominator)

Definition at line 268 of file gnc-numeric.c.

00269 {
00270   return ((a.num == b.num) && (a.denom == b.denom));
00271 }

gboolean gnc_numeric_equal gnc_numeric  a,
gnc_numeric  b
 

Equivalence predicate: Returns TRUE (1) if a and b represent the same number. That is, return TRUE if the ratios, when reduced by eliminating common factors, are identical.

Definition at line 279 of file gnc-numeric.c.

00280 {
00281   qofint128 l, r;
00282   if ((a.denom == b.denom) && (a.denom > 0))
00283   {
00284     return (a.num == b.num);
00285   }
00286   if ((a.denom > 0) && (b.denom > 0))
00287   {
00288     // return (a.num*b.denom == b.num*a.denom);
00289     l = mult128 (a.num, b.denom);
00290     r = mult128 (b.num, a.denom);
00291     return equal128 (l, r);
00292 
00293 #if ALT_WAY_OF_CHECKING_EQUALITY
00294     gnc_numeric ra = gnc_numeric_reduce (a);
00295     gnc_numeric rb = gnc_numeric_reduce (b);
00296     if (ra.denom != rb.denom) return 0;
00297     if (ra.num != rb.num) return 0;
00298     return 1;
00299 #endif
00300   }
00301   if ((a.denom < 0) && (b.denom < 0)) {
00302       l = mult128 (a.num, -a.denom);
00303       r = mult128 (b.num, -b.denom);
00304       return equal128 (l, r);
00305   } else {
00306       /* BUG: One of the numbers has a reciprocal denom, and the other
00307          does not. I just don't know to handle this case in any
00308          reasonably overflow-proof yet simple way.  So, this funtion
00309          will simply get it wrong whenever the three multiplies
00310          overflow 64-bits.  -CAS */
00311       if (a.denom < 0) {
00312           return ((a.num * -a.denom * b.denom) == b.num);
00313       } else {
00314           return (a.num == (b.num * a.denom * -b.denom));
00315       }
00316   }
00317 
00318   return ((a.num * b.denom) == (a.denom * b.num));
00319 }

gnc_numeric gnc_numeric_error GNCNumericErrorCode  error_code  ) 
 

Create a gnc_numeric object that signals the error condition noted by error_code, rather than a number.

Definition at line 1112 of file gnc-numeric.c.

01113 {
01114   return gnc_numeric_create(error_code, 0LL);
01115 }

gnc_numeric gnc_numeric_mul gnc_numeric  a,
gnc_numeric  b,
gint64  denom,
gint  how
 

Multiply a times b, returning the product. An overflow may occur if the result of the multiplication can't be represented as a ratio of 64-bit int's after removing common factors.

Definition at line 456 of file gnc-numeric.c.

00458 {
00459   gnc_numeric product, result;
00460   qofint128 bignume, bigdeno;
00461   
00462   if(gnc_numeric_check(a) || gnc_numeric_check(b)) {
00463     return gnc_numeric_error(GNC_ERROR_ARG);
00464   }
00465 
00466   if((denom == GNC_DENOM_AUTO) && 
00467      (how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_FIXED) {
00468     if(a.denom == b.denom) {
00469       denom = a.denom;
00470     }
00471     else if(b.num == 0) {
00472       denom = a.denom;
00473     }
00474     else if(a.num == 0) {
00475       denom = b.denom;
00476     }
00477     else {
00478       return gnc_numeric_error(GNC_ERROR_DENOM_DIFF);
00479     }
00480   }
00481 
00482   if((denom == GNC_DENOM_AUTO) &&
00483      ((how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_LCD)) 
00484   {
00485     denom = gnc_numeric_lcd(a, b);
00486     how   = how & GNC_NUMERIC_RND_MASK;
00487   }
00488 
00489   if(a.denom < 0) {
00490     a.num *= -a.denom;  /* BUG: overflow not handled.  */
00491     a.denom = 1;
00492   }
00493 
00494   if(b.denom < 0) {
00495     b.num *= -b.denom;  /* BUG: overflow not handled.  */
00496     b.denom = 1;
00497   }
00498 
00499   bignume = mult128 (a.num, b.num);
00500   bigdeno = mult128 (a.denom, b.denom);
00501   product.num   = a.num*b.num;
00502   product.denom = a.denom*b.denom;
00503 
00504   /* If it looks to be overflowing, try to reduce the fraction ... */
00505   if (bignume.isbig || bigdeno.isbig)
00506   {
00507     gint64 tmp;
00508     a = gnc_numeric_reduce (a);
00509     b = gnc_numeric_reduce (b);
00510     tmp = a.num;
00511     a.num = b.num;
00512     b.num = tmp;
00513     a = gnc_numeric_reduce (a);
00514     b = gnc_numeric_reduce (b);
00515 
00516     bignume = mult128 (a.num, b.num);
00517     bigdeno = mult128 (a.denom, b.denom);
00518     product.num   = a.num*b.num;
00519     product.denom = a.denom*b.denom;
00520   }
00521 
00522   /* If it its still overflowing, and rounding is allowed then round */
00523   if (bignume.isbig || bigdeno.isbig)
00524   {
00525     /* If rounding allowed, then shift until there's no 
00526      * more overflow. The conversion at the end will fix 
00527      * things up for the final value. Else overflow. */
00528     if ((how & GNC_NUMERIC_RND_MASK) == GNC_HOW_RND_NEVER)
00529     {
00530       if (bigdeno.isbig)
00531       {
00532         return gnc_numeric_error (GNC_ERROR_OVERFLOW);
00533       }
00534       product = reduce128 (bignume, product.denom);
00535       if (gnc_numeric_check (product))
00536       {
00537         return gnc_numeric_error (GNC_ERROR_OVERFLOW);
00538       }
00539     } 
00540     else 
00541     {
00542       while (bignume.isbig || bigdeno.isbig)
00543       {
00544          bignume = shift128 (bignume);
00545          bigdeno = shift128 (bigdeno);
00546       }
00547       product.num = bignume.lo;
00548       if (bignume.isneg) product.num = -product.num;
00549 
00550       product.denom = bigdeno.lo;
00551       if (0 == product.denom) 
00552       {
00553         return gnc_numeric_error (GNC_ERROR_OVERFLOW);
00554       }
00555     }
00556   }
00557   
00558 #if 0  /* currently, product denom won't ever be zero */
00559   if(product.denom < 0) {
00560     product.num   = -product.num;
00561     product.denom = -product.denom;
00562   }
00563 #endif
00564   
00565   result = gnc_numeric_convert(product, denom, how);                             
00566   return result;
00567 }

gnc_numeric gnc_numeric_mul_with_error gnc_numeric  a,
gnc_numeric  b,
gint64  denom,
gint  how,
gnc_numeric error
 

The same as gnc_numeric_mul, but uses error for accumulating conversion roundoff error.

Definition at line 1166 of file gnc-numeric.c.

01169 {
01170   gnc_numeric prod  = gnc_numeric_mul(a, b, denom, how);
01171   gnc_numeric exact = gnc_numeric_mul(a, b, GNC_DENOM_AUTO,
01172                                       GNC_HOW_DENOM_REDUCE);
01173   gnc_numeric err   = gnc_numeric_sub(prod, exact, GNC_DENOM_AUTO,
01174                                       GNC_HOW_DENOM_REDUCE);
01175   if(error) {
01176     *error = err;
01177   }
01178   return prod;
01179 }

gnc_numeric gnc_numeric_neg gnc_numeric  a  ) 
 

Negate the argument

Definition at line 708 of file gnc-numeric.c.

00708                                {
00709   if(gnc_numeric_check(a)) {
00710     return gnc_numeric_error(GNC_ERROR_ARG);
00711   }
00712   return gnc_numeric_create(- a.num, a.denom);
00713 }

gboolean gnc_numeric_negative_p gnc_numeric  a  ) 
 

Returns 1 if a < 0, otherwise returns 0.

Definition at line 172 of file gnc-numeric.c.

00173 {
00174   if(gnc_numeric_check(a)) 
00175   {
00176     return 0;
00177   }
00178   else 
00179   {
00180     if((a.num < 0) && (a.denom != 0)) 
00181     {
00182       return 1;
00183     }
00184     else 
00185     {
00186       return 0;
00187     }
00188   }
00189 }

static gint64 gnc_numeric_num gnc_numeric  a  )  [inline, static]
 

Return numerator

Definition at line 276 of file gnc-numeric.h.

00276 { return a.num; }

gboolean gnc_numeric_positive_p gnc_numeric  a  ) 
 

Returns 1 if a > 0, otherwise returns 0.

Definition at line 196 of file gnc-numeric.c.

00197 {
00198   if(gnc_numeric_check(a)) 
00199   {
00200     return 0;
00201   }
00202   else 
00203   {
00204     if((a.num > 0) && (a.denom != 0)) 
00205     {
00206       return 1;
00207     }
00208     else 
00209     {
00210       return 0;
00211     }
00212   }
00213 }

gnc_numeric gnc_numeric_reduce gnc_numeric  in  ) 
 

Return input after reducing it by Greated Common Factor (GCF) elimination

Definition at line 991 of file gnc-numeric.c.

00992 {
00993   gint64   t;
00994   gint64   num = (in.num < 0) ? (- in.num) : in.num ;
00995   gint64   denom = in.denom;
00996   gnc_numeric out;
00997 
00998   if(gnc_numeric_check(in)) 
00999   {
01000     return gnc_numeric_error(GNC_ERROR_ARG);
01001   }
01002 
01003   /* The strategy is to use Euclid's algorithm */
01004   while (denom > 0) {
01005     t = num % denom;
01006     num = denom;
01007     denom = t;
01008   }
01009   /* num now holds the GCD (Greatest Common Divisor) */
01010 
01011   /* All calculations are done on positive num, since it's not 
01012    * well defined what % does for negative values */
01013   out.num   = in.num / num;
01014   out.denom = in.denom / num;
01015   return out;
01016 }

gint gnc_numeric_same gnc_numeric  a,
gnc_numeric  b,
gint64  denom,
gint  how
 

Equivalence predicate: Convert both a and b to denom using the specified DENOM and method HOW, and compare numerators the results using gnc_numeric_equal.

For example, if a == 7/16 and b == 3/4, gnc_numeric_same(a, b, 2, GNC_HOW_RND_TRUNC) == 1 because both 7/16 and 3/4 round to 1/2 under truncation. However, gnc_numeric_same(a, b, 2, GNC_HOW_RND_ROUND) == 0 because 7/16 rounds to 1/2 under unbiased rounding but 3/4 rounds to 2/2.

Definition at line 329 of file gnc-numeric.c.

00330                            {
00331   gnc_numeric aconv, bconv;
00332   
00333   aconv = gnc_numeric_convert(a, denom, how);
00334   bconv = gnc_numeric_convert(b, denom, how);
00335   
00336   return(gnc_numeric_equal(aconv, bconv));
00337 }

gnc_numeric gnc_numeric_sub gnc_numeric  a,
gnc_numeric  b,
gint64  denom,
gint  how
 

Return a-b.

Definition at line 437 of file gnc-numeric.c.

00439 {
00440   gnc_numeric nb;
00441   if(gnc_numeric_check(a) || gnc_numeric_check(b)) 
00442   {
00443     return gnc_numeric_error(GNC_ERROR_ARG);
00444   }
00445 
00446   nb = b;
00447   nb.num = -nb.num;
00448   return gnc_numeric_add (a, nb, denom, how);
00449 }

static gnc_numeric gnc_numeric_sub_fixed gnc_numeric  a,
gnc_numeric  b
[inline, static]
 

Shortcut for most common case: gnc_numeric_sub(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_FIXED | GNC_HOW_RND_NEVER);

Definition at line 390 of file gnc-numeric.h.

00390                                                                 {
00391   return gnc_numeric_sub(a, b, GNC_DENOM_AUTO,
00392                          GNC_HOW_DENOM_FIXED | GNC_HOW_RND_NEVER);
00393 }

gnc_numeric gnc_numeric_sub_with_error gnc_numeric  a,
gnc_numeric  b,
gint64  denom,
gint  how,
gnc_numeric error
 

The same as gnc_numeric_sub, but uses error for accumulating conversion roundoff error.

Definition at line 1145 of file gnc-numeric.c.

01148 {
01149   gnc_numeric diff  = gnc_numeric_sub(a, b, denom, how);
01150   gnc_numeric exact = gnc_numeric_sub(a, b, GNC_DENOM_AUTO,
01151                                       GNC_HOW_DENOM_REDUCE);
01152   gnc_numeric err   = gnc_numeric_sub(diff, exact, GNC_DENOM_AUTO, 
01153                                       GNC_HOW_DENOM_REDUCE);
01154   if(error) {
01155     *error = err;
01156   }
01157   return diff;
01158 }

gdouble gnc_numeric_to_double gnc_numeric  in  ) 
 

Convert numeric to floating-point value.

Definition at line 1095 of file gnc-numeric.c.

01096 {
01097   if(in.denom > 0) 
01098   {
01099     return (double)in.num/(double)in.denom;
01100   }
01101   else 
01102   {
01103     return (double)(in.num * -in.denom);
01104   }
01105 }

gchar* gnc_numeric_to_string gnc_numeric  n  ) 
 

Convert to string. The returned buffer is to be g_free'd by the caller (it was allocated through g_strdup)

Definition at line 1207 of file gnc-numeric.c.

01208 {
01209   gchar *result;
01210   gint64 tmpnum = n.num;
01211   gint64 tmpdenom = n.denom;
01212 
01213   result = g_strdup_printf("%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, tmpnum, tmpdenom);
01214 
01215   return result;
01216 }

static gnc_numeric gnc_numeric_zero void   )  [inline, static]
 

create a zero-value gnc_numeric

Definition at line 250 of file gnc-numeric.h.

00250 { return gnc_numeric_create(0, 1); }

gboolean gnc_numeric_zero_p gnc_numeric  a  ) 
 

Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.

Definition at line 148 of file gnc-numeric.c.

00149 {
00150   if(gnc_numeric_check(a)) 
00151   {
00152     return 0;
00153   }
00154   else 
00155   {
00156     if((a.num == 0) && (a.denom != 0)) 
00157     {
00158       return 1;
00159     }
00160     else 
00161     {
00162       return 0;
00163     }
00164   }
00165 }

gboolean string_to_gnc_numeric const gchar *  str,
gnc_numeric n
 

Read a gnc_numeric from str, skipping any leading whitespace. Return TRUE on success and store the resulting value in "n". Return NULL on error.

Definition at line 1235 of file gnc-numeric.c.

01236 {
01237   size_t num_read;
01238   gint64 tmpnum;
01239   gint64 tmpdenom;
01240     
01241   if(!str) return FALSE;
01242 
01243 #ifdef GNC_DEPRECATED
01244   /* must use "<" here because %n's effects aren't well defined */
01245   if(sscanf(str, " " GNC_SCANF_LLD "/" GNC_SCANF_LLD "%n",
01246             &tmpnum, &tmpdenom, &num_read) < 2) {
01247     return FALSE;
01248   }
01249 #else
01250   tmpnum = strtoll (str, NULL, 0);
01251   str = strchr (str, '/');
01252   if (!str) return FALSE;
01253   str ++;
01254   tmpdenom = strtoll (str, NULL, 0);
01255   num_read = strspn (str, "0123456789");
01256 #endif
01257   n->num = tmpnum;
01258   n->denom = tmpdenom;
01259   return TRUE;
01260 }


Generated on Fri May 12 18:00:34 2006 for QOF by  doxygen 1.4.4