Numeric: Rational Number Handling w/ Rounding Error Control
[Query Object Framework]


Detailed Description

The 'Numeric' functions provide a way of working with rational numbers while maintaining strict control over rounding errors when adding rationals with different denominators. The Numeric class is primarily used for working with monetary amounts, where the denominator typically represents the smallest fraction of the currency (e.g. pennies, centimes). The numeric class can handle any fraction (e.g. twelfth's) and is not limited to fractions that are powers of ten.

A 'Numeric' value represents a number in rational form, with a 64-bit integer as numerator and denominator. Rationals are ideal for many uses, such as performing exact, roundoff-error-free addition and multiplication, but 64-bit rationals do not have the dynamic range of floating point numbers.

EXAMPLE
-------
The following program finds the best gnc_numeric approximation to the math.h constant M_PI given a maximum denominator. For large denominators, the gnc_numeric approximation is accurate to more decimal places than will generally be needed, but in some cases this may not be good enough. For example,

    M_PI                   = 3.14159265358979323846
    245850922 / 78256779   = 3.14159265358979311599  (16 sig figs)
    3126535 / 995207       = 3.14159265358865047446  (12 sig figs)
    355 / 113              = 3.14159292035398252096  (7 sig figs)

#include <glib.h>
#include <qof.h>
#include <math.h>

int
main(int argc, char ** argv)
{
  gnc_numeric approx, best;
  double err, best_err=1.0;
  double m_pi = M_PI;
  gint64 denom;
  gint64 max;

  sscanf(argv[1], "%Ld", &max);
  
  for (denom = 1; denom < max; denom++)
  {
    approx = double_to_gnc_numeric (m_pi, denom, GNC_RND_ROUND);
    err    = m_pi - gnc_numeric_to_double (approx);
    if (fabs (err) < fabs (best_err))
    {
      best = approx;
      best_err = err;
      printf ("%Ld / %Ld = %.30f\n", gnc_numeric_num (best),
              gnc_numeric_denom (best), gnc_numeric_to_double (best));
    }
  }
}


Files

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

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)
double 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)
int 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)
int 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 275 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 278 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 248 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 163 of file gnc-numeric.h.


Typedef Documentation

typedef struct _gnc_numeric gnc_numeric
 

An rational-number type.

This is a rational number, defined by numerator and denominator.

Definition at line 108 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 176 of file gnc-numeric.h.

00176      { 
00178   GNC_HOW_RND_FLOOR            = 0x01, 
00179 
00181   GNC_HOW_RND_CEIL             = 0x02,  
00182 
00184   GNC_HOW_RND_TRUNC            = 0x03,
00185 
00187   GNC_HOW_RND_PROMOTE          = 0x04,
00188 
00192   GNC_HOW_RND_ROUND_HALF_DOWN  = 0x05, 
00193 
00197   GNC_HOW_RND_ROUND_HALF_UP    = 0x06, 
00198 
00204   GNC_HOW_RND_ROUND            = 0x07, 
00205 
00209   GNC_HOW_RND_NEVER            = 0x08
00210 };

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 213 of file gnc-numeric.h.

00213      { 
00219   GNC_HOW_DENOM_EXACT  = 0x10, 
00220 
00226   GNC_HOW_DENOM_REDUCE = 0x20,
00227 
00231   GNC_HOW_DENOM_LCD    = 0x30,
00232 
00237   GNC_HOW_DENOM_FIXED  = 0x40,
00238 
00242   GNC_HOW_DENOM_SIGFIG = 0x50
00243 };

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 252 of file gnc-numeric.h.

00252              {
00253   GNC_ERROR_OK         =  0,   
00254   GNC_ERROR_ARG        = -1,   
00255   GNC_ERROR_OVERFLOW   = -2,   
00258   GNC_ERROR_DENOM_DIFF = -3,   
00259 
00262   GNC_ERROR_REMAINDER  = -4   
00263 } 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 999 of file gnc-numeric.c.

01000 {
01001   gnc_numeric out;
01002   gint64 int_part=0;
01003   double frac_part;
01004   gint64 frac_int=0;
01005   double logval; 
01006   double sigfigs;
01007 
01008   if((denom == GNC_DENOM_AUTO) && (how & GNC_HOW_DENOM_SIGFIG)) 
01009   {
01010     if(fabs(in) < 10e-20) {
01011       logval = 0;
01012     }
01013     else {
01014       logval   = log10(fabs(in));
01015       logval   = ((logval > 0.0) ? 
01016                   (floor(logval)+1.0) : (ceil(logval)));
01017     }
01018     sigfigs  = GNC_HOW_GET_SIGFIGS(how);
01019     if(sigfigs-logval >= 0) {
01020       denom    = (gint64)(pow(10, sigfigs-logval));
01021     }
01022     else {
01023       denom    = -((gint64)(pow(10, logval-sigfigs)));
01024     }
01025 
01026     how =  how & ~GNC_HOW_DENOM_SIGFIG & ~GNC_NUMERIC_SIGFIGS_MASK;
01027   }
01028 
01029   int_part  = (gint64)(floor(fabs(in)));
01030   frac_part = in - (double)int_part;
01031   
01032   int_part = int_part * denom;
01033   frac_part = frac_part * (double)denom;
01034 
01035   switch(how & GNC_NUMERIC_RND_MASK) {
01036   case GNC_HOW_RND_FLOOR:
01037     frac_int = (gint64)floor(frac_part);
01038     break;
01039 
01040   case GNC_HOW_RND_CEIL:
01041     frac_int = (gint64)ceil(frac_part);
01042     break;
01043 
01044   case GNC_HOW_RND_TRUNC:
01045     frac_int = (gint64)frac_part;
01046     break;
01047     
01048   case GNC_HOW_RND_ROUND:
01049   case GNC_HOW_RND_ROUND_HALF_UP:
01050     frac_int = (gint64)rint(frac_part);
01051     break;
01052 
01053   case GNC_HOW_RND_NEVER:
01054     frac_int = (gint64)floor(frac_part);
01055     if(frac_part != (double) frac_int) {
01056       /* signal an error */
01057     }
01058     break;
01059   }
01060 
01061   out.num   = int_part + frac_int; 
01062   out.denom = denom;
01063   return out;
01064 }

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 1195 of file gnc-numeric.c.

01196 {
01197   static char buff[1000];
01198   static char *p = buff;
01199   gint64 tmpnum = n.num;
01200   gint64 tmpdenom = n.denom;
01201 
01202   p+= 100;
01203   if (p-buff >= 1000) p = buff;
01204    
01205   sprintf(p, "%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, tmpnum, tmpdenom);
01206 
01207   return p;
01208 }

gnc_numeric gnc_numeric_abs gnc_numeric  a  ) 
 

Return the absolute value of the argument

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

00703 {
00704   if(gnc_numeric_check(a)) {
00705     return gnc_numeric_error(GNC_ERROR_ARG);
00706   }
00707   return gnc_numeric_create(ABS(a.num), a.denom);
00708 }

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

Return a+b.

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

00329 {
00330   gnc_numeric sum;
00331   
00332   if(gnc_numeric_check(a) || gnc_numeric_check(b)) 
00333   {
00334     return gnc_numeric_error(GNC_ERROR_ARG);
00335   }
00336 
00337   if((denom == GNC_DENOM_AUTO) && 
00338      (how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_FIXED) 
00339   {
00340     if(a.denom == b.denom) {
00341       denom = a.denom;
00342     }
00343     else if(b.num == 0) {
00344       denom = a.denom;
00345       b.denom = a.denom;
00346     }
00347     else if(a.num == 0) {
00348       denom = b.denom;
00349       a.denom = b.denom;
00350     }
00351     else {
00352       return gnc_numeric_error(GNC_ERROR_DENOM_DIFF);
00353     }
00354   }
00355   
00356   if(a.denom < 0) 
00357   {
00358     a.num *= a.denom;
00359     a.denom = 1;
00360   }
00361 
00362   if(b.denom < 0) 
00363   {
00364     b.num *= b.denom;
00365     b.denom = 1;
00366   }
00367 
00368   /* Get an exact answer.. same denominator is the common case. */ 
00369   if(a.denom == b.denom) 
00370   {
00371     sum.num = a.num + b.num;
00372     sum.denom = a.denom;
00373   }
00374   else 
00375   {
00376     /* We want to do this:
00377      *    sum.num = a.num*b.denom + b.num*a.denom;
00378      *    sum.denom = a.denom*b.denom;
00379      * but the multiply could overflow.  
00380      * Computing the LCD minimizes likelyhood of overflow
00381      */
00382     gint64 lcd;
00383     qofint128 ca, cb, cab;
00384     lcd = gnc_numeric_lcd(a,b);
00385     if (GNC_ERROR_ARG == lcd)
00386     {
00387        return gnc_numeric_error(GNC_ERROR_OVERFLOW);
00388     }
00389     ca = mult128 (a.num, lcd/a.denom);
00390     if (ca.isbig) return gnc_numeric_error(GNC_ERROR_OVERFLOW);
00391 
00392     cb = mult128 (b.num, lcd/b.denom);
00393     if (cb.isbig) return gnc_numeric_error(GNC_ERROR_OVERFLOW);
00394 
00395     cab = add128 (ca, cb);
00396     if (cab.isbig) return gnc_numeric_error(GNC_ERROR_OVERFLOW);
00397     
00398     sum.num   = cab.lo;
00399     if (cab.isneg) sum.num = -sum.num;
00400     sum.denom = lcd;
00401   }
00402   
00403   if((denom == GNC_DENOM_AUTO) &&
00404      ((how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_LCD)) 
00405   {
00406     denom = gnc_numeric_lcd(a, b);
00407     how   = how & GNC_NUMERIC_RND_MASK;
00408   }
00409   
00410   return gnc_numeric_convert(sum, denom, how);                             
00411 }

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 426 of file gnc-numeric.h.

00426                                                                 {
00427    return gnc_numeric_add(a, b, GNC_DENOM_AUTO,
00428                          GNC_HOW_DENOM_FIXED | GNC_HOW_RND_NEVER);
00429 }

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 1099 of file gnc-numeric.c.

01102 {
01103 
01104   gnc_numeric sum   = gnc_numeric_add(a, b, denom, how);
01105   gnc_numeric exact = gnc_numeric_add(a, b, GNC_DENOM_AUTO, 
01106                                       GNC_HOW_DENOM_REDUCE);
01107   gnc_numeric err   = gnc_numeric_sub(sum, exact, GNC_DENOM_AUTO,
01108                                       GNC_HOW_DENOM_REDUCE);
01109 
01110   if(error) {
01111     *error = err;
01112   }
01113   return sum;
01114 }

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 }

int 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   aa = a.num * a.denom;
00247   bb = b.num * b.denom;
00248 
00249   if(aa == bb) return 0;
00250   if(aa > bb) return 1;
00251   return -1;
00252 }

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 715 of file gnc-numeric.c.

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

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 287 of file gnc-numeric.h.

00287                                                          {
00288   gnc_numeric out;
00289   out.num = num;
00290   out.denom = denom;
00291   return out;
00292 }

static gint64 gnc_numeric_denom gnc_numeric  a  )  [inline, static]
 

Return denominator

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

00325 { 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 556 of file gnc-numeric.c.

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

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 1163 of file gnc-numeric.c.

01166 {
01167   gnc_numeric quot  = gnc_numeric_div(a, b, denom, how);
01168   gnc_numeric exact = gnc_numeric_div(a, b, GNC_DENOM_AUTO, 
01169                                       GNC_HOW_DENOM_REDUCE);
01170   gnc_numeric err   = gnc_numeric_sub(quot, exact, 
01171                                       GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
01172   if(error) {
01173     *error = err;
01174   }
01175   return quot;
01176 }

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 260 of file gnc-numeric.c.

00261 {
00262   return ((a.num == b.num) && (a.denom == b.denom));
00263 }

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 271 of file gnc-numeric.c.

00272 {
00273   if ((a.denom == b.denom) && (a.denom > 0))
00274   {
00275     return (a.num == b.num);
00276   }
00277   if ((a.denom > 0) && (b.denom > 0))
00278   {
00279     // return (a.num*b.denom == b.num*a.denom);
00280     qofint128 l = mult128 (a.num, b.denom);
00281     qofint128 r = mult128 (b.num, a.denom);
00282     return equal128 (l, r);
00283 
00284 #if ALT_WAY_OF_CHECKING_EQUALITY
00285     gnc_numeric ra = gnc_numeric_reduce (a);
00286     gnc_numeric rb = gnc_numeric_reduce (b);
00287     if (ra.denom != rb.denom) return 0;
00288     if (ra.num != rb.num) return 0;
00289     return 1;
00290 #endif
00291   }
00292   if ((a.denom < 0) && (b.denom < 0))
00293   {    
00294     return ((a.num * b.denom) == (a.denom * b.num));
00295   }
00296   else 
00297   {
00298     return 0;
00299   }
00300 }

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 1088 of file gnc-numeric.c.

01089 {
01090   return gnc_numeric_create(error_code, 0LL);
01091 }

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 437 of file gnc-numeric.c.

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

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 1142 of file gnc-numeric.c.

01145 {
01146   gnc_numeric prod  = gnc_numeric_mul(a, b, denom, how);
01147   gnc_numeric exact = gnc_numeric_mul(a, b, GNC_DENOM_AUTO,
01148                                       GNC_HOW_DENOM_REDUCE);
01149   gnc_numeric err   = gnc_numeric_sub(prod, exact, GNC_DENOM_AUTO,
01150                                       GNC_HOW_DENOM_REDUCE);
01151   if(error) {
01152     *error = err;
01153   }
01154   return prod;
01155 }

gnc_numeric gnc_numeric_neg gnc_numeric  a  ) 
 

Negate the argument

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

00689                                {
00690   if(gnc_numeric_check(a)) {
00691     return gnc_numeric_error(GNC_ERROR_ARG);
00692   }
00693   return gnc_numeric_create(- a.num, a.denom);
00694 }

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 322 of file gnc-numeric.h.

00322 { 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 967 of file gnc-numeric.c.

00968 {
00969   gint64   t;
00970   gint64   num = (in.num < 0) ? (- in.num) : in.num ;
00971   gint64   denom = in.denom;
00972   gnc_numeric out;
00973 
00974   if(gnc_numeric_check(in)) 
00975   {
00976     return gnc_numeric_error(GNC_ERROR_ARG);
00977   }
00978 
00979   /* The strategy is to use Euclid's algorithm */
00980   while (denom > 0) {
00981     t = num % denom;
00982     num = denom;
00983     denom = t;
00984   }
00985   /* num now holds the GCD (Greatest Common Divisor) */
00986 
00987   /* All calculations are done on positive num, since it's not 
00988    * well defined what % does for negative values */
00989   out.num   = in.num / num;
00990   out.denom = in.denom / num;
00991   return out;
00992 }

int 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 310 of file gnc-numeric.c.

00311                            {
00312   gnc_numeric aconv, bconv;
00313   
00314   aconv = gnc_numeric_convert(a, denom, how);
00315   bconv = gnc_numeric_convert(b, denom, how);
00316   
00317   return(gnc_numeric_equal(aconv, bconv));
00318 }

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

Return a-b.

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

00420 {
00421   gnc_numeric nb;
00422   if(gnc_numeric_check(a) || gnc_numeric_check(b)) 
00423   {
00424     return gnc_numeric_error(GNC_ERROR_ARG);
00425   }
00426 
00427   nb = b;
00428   nb.num = -nb.num;
00429   return gnc_numeric_add (a, nb, denom, how);
00430 }

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 436 of file gnc-numeric.h.

00436                                                                 {
00437   return gnc_numeric_sub(a, b, GNC_DENOM_AUTO,
00438                          GNC_HOW_DENOM_FIXED | GNC_HOW_RND_NEVER);
00439 }

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 1121 of file gnc-numeric.c.

01124 {
01125   gnc_numeric diff  = gnc_numeric_sub(a, b, denom, how);
01126   gnc_numeric exact = gnc_numeric_sub(a, b, GNC_DENOM_AUTO,
01127                                       GNC_HOW_DENOM_REDUCE);
01128   gnc_numeric err   = gnc_numeric_sub(diff, exact, GNC_DENOM_AUTO, 
01129                                       GNC_HOW_DENOM_REDUCE);
01130   if(error) {
01131     *error = err;
01132   }
01133   return diff;
01134 }

double gnc_numeric_to_double gnc_numeric  in  ) 
 

Convert numeric to floating-point value.

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

01072 {
01073   if(in.denom > 0) 
01074   {
01075     return (double)in.num/(double)in.denom;
01076   }
01077   else 
01078   {
01079     return (double)(in.num * in.denom);
01080   }
01081 }

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 1183 of file gnc-numeric.c.

01184 {
01185   gchar *result;
01186   gint64 tmpnum = n.num;
01187   gint64 tmpdenom = n.denom;
01188 
01189   result = g_strdup_printf("%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, tmpnum, tmpdenom);
01190 
01191   return result;
01192 }

static gnc_numeric gnc_numeric_zero void   )  [inline, static]
 

create a zero-value gnc_numeric

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

00296 { 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 1211 of file gnc-numeric.c.

01212 {
01213   size_t num_read;
01214   gint64 tmpnum;
01215   gint64 tmpdenom;
01216     
01217   if(!str) return FALSE;
01218 
01219 #ifdef GNC_DEPRECATED
01220   /* must use "<" here because %n's effects aren't well defined */
01221   if(sscanf(str, " " GNC_SCANF_LLD "/" GNC_SCANF_LLD "%n",
01222             &tmpnum, &tmpdenom, &num_read) < 2) {
01223     return FALSE;
01224   }
01225 #else
01226   tmpnum = strtoll (str, NULL, 0);
01227   str = strchr (str, '/');
01228   if (!str) return FALSE;
01229   str ++;
01230   tmpdenom = strtoll (str, NULL, 0);
01231   num_read = strspn (str, "0123456789");
01232 #endif
01233   n->num = tmpnum;
01234   n->denom = tmpdenom;
01235   return TRUE;
01236 }


Generated on Fri Oct 21 15:49:58 2005 for QOF by  doxygen 1.4.5