Numeric: Rational Number Handling with 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.

See QofNumeric Example


Files

file  qofnumeric.h
 An exact-rational-number library for QOF.

Modules

 Math128

Data Structures

struct  _QofNumeric

Standard Arguments to most functions

Most of the QofNumeric arithmetic functions take two arguments in addition to their numeric args: 'denom', which is the denominator to use in the output QofNumeric 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: QOF_DENOM_AUTO -- compute denominator exactly integer n -- Force the denominator of the result to be this integer QOF_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: QOF_HOW_RND_FLOOR QOF_HOW_RND_CEIL QOF_HOW_RND_TRUNC QOF_HOW_RND_PROMOTE QOF_HOW_RND_ROUND_HALF_DOWN QOF_HOW_RND_ROUND_HALF_UP QOF_HOW_RND_ROUND QOF_HOW_RND_NEVER

The denominator type specifies how to compute a denominator if QOF_DENOM_AUTO is specified as the 'denom'. Valid denominator types are: QOF_HOW_DENOM_EXACT QOF_HOW_DENOM_REDUCE QOF_HOW_DENOM_LCD QOF_HOW_DENOM_FIXED QOF_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 QOF_DENOM_AUTO as 'denom' and QOF_HOW_DENOM_REDUCE| QOF_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 QOF_DENOM_AUTO as 'denom' and QOF_HOW_DENOM_FIXED | QOF_HOW_RND_NEVER as 'how'.

enum  {
  QOF_HOW_RND_FLOOR = 0x01, QOF_HOW_RND_CEIL = 0x02, QOF_HOW_RND_TRUNC = 0x03, QOF_HOW_RND_PROMOTE = 0x04,
  QOF_HOW_RND_ROUND_HALF_DOWN = 0x05, QOF_HOW_RND_ROUND_HALF_UP = 0x06, QOF_HOW_RND_ROUND = 0x07, QOF_HOW_RND_NEVER = 0x08
}
 Rounding/Truncation modes for operations. More...
enum  {
  QOF_HOW_DENOM_EXACT = 0x10, QOF_HOW_DENOM_REDUCE = 0x20, QOF_HOW_DENOM_LCD = 0x30, QOF_HOW_DENOM_FIXED = 0x40,
  QOF_HOW_DENOM_SIGFIG = 0x50
}
enum  QofNumericErrorCode {
  QOF_ERROR_OK = 0, QOF_ERROR_ARG = -1, QOF_ERROR_OVERFLOW = -2, QOF_ERROR_DENOM_DIFF = -3,
  QOF_ERROR_REMAINDER = -4
}
#define QOF_NUMERIC_RND_MASK   0x0000000f
 bitmasks for HOW flags.
#define QOF_NUMERIC_DENOM_MASK   0x000000f0
#define QOF_NUMERIC_SIGFIGS_MASK   0x0000ff00
#define QOF_HOW_DENOM_SIGFIGS(n)   ( ((( n ) & 0xff) << 8) | QOF_HOW_DENOM_SIGFIG)
#define QOF_HOW_GET_SIGFIGS(a)   ( (( a ) & 0xff00 ) >> 8)
#define QOF_DENOM_AUTO   0
#define QOF_DENOM_RECIPROCAL(a)   (- ( a ))

Constructors

static QofNumeric qof_numeric_create (gint64 num, gint64 denom)
static QofNumeric qof_numeric_zero (void)
QofNumeric qof_numeric_from_double (gdouble in, gint64 denom, gint how)
gboolean qof_numeric_from_string (const gchar *str, QofNumeric *n)
QofNumeric qof_numeric_error (QofNumericErrorCode error_code)

Value Accessors

static gint64 qof_numeric_num (QofNumeric a)
static gint64 qof_numeric_denom (QofNumeric a)
gdouble qof_numeric_to_double (QofNumeric in)
gchar * qof_numeric_to_string (QofNumeric n)
gchar * qof_numeric_dbg_to_string (QofNumeric n)

Comparisons and Predicates

QofNumericErrorCode qof_numeric_check (QofNumeric a)
gint qof_numeric_compare (QofNumeric a, QofNumeric b)
gboolean qof_numeric_zero_p (QofNumeric a)
gboolean qof_numeric_negative_p (QofNumeric a)
gboolean qof_numeric_positive_p (QofNumeric a)
gboolean qof_numeric_eq (QofNumeric a, QofNumeric b)
gboolean qof_numeric_equal (QofNumeric a, QofNumeric b)
gint qof_numeric_same (QofNumeric a, QofNumeric b, gint64 denom, gint how)

Arithmetic Operations

QofNumeric qof_numeric_add (QofNumeric a, QofNumeric b, gint64 denom, gint how)
QofNumeric qof_numeric_sub (QofNumeric a, QofNumeric b, gint64 denom, gint how)
QofNumeric qof_numeric_mul (QofNumeric a, QofNumeric b, gint64 denom, gint how)
QofNumeric qof_numeric_div (QofNumeric x, QofNumeric y, gint64 denom, gint how)
QofNumeric qof_numeric_neg (QofNumeric a)
QofNumeric qof_numeric_abs (QofNumeric a)
static QofNumeric qof_numeric_add_fixed (QofNumeric a, QofNumeric b)
static QofNumeric qof_numeric_sub_fixed (QofNumeric a, QofNumeric b)

Arithmetic Functions with Exact Error Returns

QofNumeric qof_numeric_add_with_error (QofNumeric a, QofNumeric b, gint64 denom, gint how, QofNumeric *error)
QofNumeric qof_numeric_sub_with_error (QofNumeric a, QofNumeric b, gint64 denom, gint how, QofNumeric *error)
QofNumeric qof_numeric_mul_with_error (QofNumeric a, QofNumeric b, gint64 denom, gint how, QofNumeric *error)
QofNumeric qof_numeric_div_with_error (QofNumeric a, QofNumeric b, gint64 denom, gint how, QofNumeric *error)

Change Denominator

QofNumeric qof_numeric_convert (QofNumeric in, gint64 denom, gint how)
QofNumeric qof_numeric_convert_with_error (QofNumeric in, gint64 denom, gint how, QofNumeric *error)
QofNumeric qof_numeric_reduce (QofNumeric in)

Deprecated, backwards-compatible definitions

#define QOF_RND_FLOOR   QOF_HOW_RND_FLOOR
#define QOF_RND_CEIL   QOF_HOW_RND_CEIL
#define QOF_RND_TRUNC   QOF_HOW_RND_TRUNC
#define QOF_RND_PROMOTE   QOF_HOW_RND_PROMOTE
#define QOF_RND_ROUND_HALF_DOWN   QOF_HOW_RND_ROUND_HALF_DOWN
#define QOF_RND_ROUND_HALF_UP   QOF_HOW_RND_ROUND_HALF_UP
#define QOF_RND_ROUND   QOF_HOW_RND_ROUND
#define QOF_RND_NEVER   QOF_HOW_RND_NEVER
#define QOF_DENOM_EXACT   QOF_HOW_DENOM_EXACT
#define QOF_DENOM_REDUCE   QOF_HOW_DENOM_REDUCE
#define QOF_DENOM_LCD   QOF_HOW_DENOM_LCD
#define QOF_DENOM_FIXED   QOF_HOW_DENOM_FIXED
#define QOF_DENOM_SIGFIG   QOF_HOW_DENOM_SIGFIG
#define QOF_DENOM_SIGFIGS(X)   QOF_HOW_DENOM_SIGFIGS(X)
#define QOF_NUMERIC_GET_SIGFIGS(X)   QOF_HOW_GET_SIGFIGS(X)

Typedefs

typedef struct _QofNumeric QofNumeric
 A rational-number type.


Define Documentation

#define QOF_DENOM_AUTO   0

Values that can be passed as the 'denom' argument. The include a positive number n to be used as the denominator of the output value. Other possibilities include the list below: Compute an appropriate denominator automatically. Flags in the 'how' argument will specify how to compute the denominator.

Definition at line 231 of file qofnumeric.h.

#define QOF_DENOM_RECIPROCAL (  )     (- ( a ))

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

Definition at line 234 of file qofnumeric.h.

#define QOF_HOW_DENOM_SIGFIGS (  )     ( ((( n ) & 0xff) << 8) | QOF_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 203 of file qofnumeric.h.

#define QOF_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 QOF_HOW_DENOM_SIGFIG

Definition at line 116 of file qofnumeric.h.


Typedef Documentation

typedef struct _QofNumeric QofNumeric

A rational-number type.

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

Definition at line 61 of file qofnumeric.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:
QOF_HOW_RND_FLOOR  Round toward -infinity
QOF_HOW_RND_CEIL  Round toward +infinity
QOF_HOW_RND_TRUNC  Truncate fractions (round toward zero)
QOF_HOW_RND_PROMOTE  Promote fractions (round away from zero)
QOF_HOW_RND_ROUND_HALF_DOWN  Round to the nearest integer, rounding toward zero when there are two equidistant nearest integers.
QOF_HOW_RND_ROUND_HALF_UP  Round to the nearest integer, rounding away from zero when there are two equidistant nearest integers.
QOF_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.
QOF_HOW_RND_NEVER  Never round at all, and signal an error if there is a fractional result in a computation.

Definition at line 129 of file qofnumeric.h.

00130 {
00132     QOF_HOW_RND_FLOOR = 0x01,
00133 
00135     QOF_HOW_RND_CEIL = 0x02,
00136 
00138     QOF_HOW_RND_TRUNC = 0x03,
00139 
00141     QOF_HOW_RND_PROMOTE = 0x04,
00142 
00146     QOF_HOW_RND_ROUND_HALF_DOWN = 0x05,
00147 
00151     QOF_HOW_RND_ROUND_HALF_UP = 0x06,
00152 
00158     QOF_HOW_RND_ROUND = 0x07,
00159 
00163     QOF_HOW_RND_NEVER = 0x08
00164 };

anonymous enum

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

Enumerator:
QOF_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.
QOF_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.
QOF_HOW_DENOM_LCD  Find the least common multiple of the arguments' denominators and use that as the denominator of the result.
QOF_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.
QOF_HOW_DENOM_SIGFIG  Round to the number of significant figures given in the rounding instructions by the QOF_HOW_DENOM_SIGFIGS () macro.

Definition at line 167 of file qofnumeric.h.

00168 {
00174     QOF_HOW_DENOM_EXACT = 0x10,
00175 
00181     QOF_HOW_DENOM_REDUCE = 0x20,
00182 
00186     QOF_HOW_DENOM_LCD = 0x30,
00187 
00192     QOF_HOW_DENOM_FIXED = 0x40,
00193 
00197     QOF_HOW_DENOM_SIGFIG = 0x50
00198 };

enum QofNumericErrorCode

Error codes

Enumerator:
QOF_ERROR_OK  No error
QOF_ERROR_ARG  Argument is not a valid number
QOF_ERROR_OVERFLOW  Intermediate result overflow
QOF_ERROR_DENOM_DIFF  QOF_HOW_DENOM_FIXED was specified, but argument denominators differed.
QOF_ERROR_REMAINDER  QOF_HOW_RND_NEVER was specified, but the result could not be converted to the desired denominator without a remainder.

Definition at line 207 of file qofnumeric.h.

00208 {
00209     QOF_ERROR_OK = 0,      
00210     QOF_ERROR_ARG = -1,    
00211     QOF_ERROR_OVERFLOW = -2,   
00214     QOF_ERROR_DENOM_DIFF = -3,
00215 
00218     QOF_ERROR_REMAINDER = -4
00219 } QofNumericErrorCode;


Function Documentation

QofNumeric qof_numeric_abs ( QofNumeric  a  ) 

Return the absolute value of the argument

Definition at line 650 of file qofnumeric.c.

00651 {
00652     if (qof_numeric_check (a))
00653         return qof_numeric_error (QOF_ERROR_ARG);
00654     return qof_numeric_create (ABS (a.num), a.denom);
00655 }

QofNumeric qof_numeric_add ( QofNumeric  a,
QofNumeric  b,
gint64  denom,
gint  how 
)

Return a+b.

Definition at line 300 of file qofnumeric.c.

00301 {
00302     QofNumeric sum;
00303 
00304     if (qof_numeric_check (a) || qof_numeric_check (b))
00305         return qof_numeric_error (QOF_ERROR_ARG);
00306 
00307     if ((denom == QOF_DENOM_AUTO) &&
00308         (how & QOF_NUMERIC_DENOM_MASK) == QOF_HOW_DENOM_FIXED)
00309     {
00310         if (a.denom == b.denom)
00311             denom = a.denom;
00312         else if (b.num == 0)
00313         {
00314             denom = a.denom;
00315             b.denom = a.denom;
00316         }
00317         else if (a.num == 0)
00318         {
00319             denom = b.denom;
00320             a.denom = b.denom;
00321         }
00322         else
00323             return qof_numeric_error (QOF_ERROR_DENOM_DIFF);
00324     }
00325 
00326     if (a.denom < 0)
00327     {
00328         a.num *= -a.denom;      /* BUG: overflow not handled.  */
00329         a.denom = 1;
00330     }
00331 
00332     if (b.denom < 0)
00333     {
00334         b.num *= -b.denom;      /* BUG: overflow not handled.  */
00335         b.denom = 1;
00336     }
00337 
00338     /* Get an exact answer.. same denominator is the common case. */
00339     if (a.denom == b.denom)
00340     {
00341         sum.num = a.num + b.num;    /* BUG: overflow not handled.  */
00342         sum.denom = a.denom;
00343     }
00344     else
00345     {
00346         /* We want to do this:
00347          *    sum.num = a.num*b.denom + b.num*a.denom;
00348          *    sum.denom = a.denom*b.denom;
00349          * but the multiply could overflow.  
00350          * Computing the LCD minimizes likelihood of overflow
00351          */
00352         gint64 lcd;
00353         QofInt128 ca, cb, cab;
00354 
00355         lcd = qof_numeric_lcd (a, b);
00356         if (QOF_ERROR_ARG == lcd)
00357             return qof_numeric_error (QOF_ERROR_OVERFLOW);
00358         ca = mult128 (a.num, lcd / a.denom);
00359         if (ca.isbig)
00360             return qof_numeric_error (QOF_ERROR_OVERFLOW);
00361         cb = mult128 (b.num, lcd / b.denom);
00362         if (cb.isbig)
00363             return qof_numeric_error (QOF_ERROR_OVERFLOW);
00364         cab = add128 (ca, cb);
00365         if (cab.isbig)
00366             return qof_numeric_error (QOF_ERROR_OVERFLOW);
00367         sum.num = cab.lo;
00368         if (cab.isneg)
00369             sum.num = -sum.num;
00370         sum.denom = lcd;
00371     }
00372 
00373     if ((denom == QOF_DENOM_AUTO) &&
00374         ((how & QOF_NUMERIC_DENOM_MASK) == QOF_HOW_DENOM_LCD))
00375     {
00376         denom = qof_numeric_lcd (a, b);
00377         how = how & QOF_NUMERIC_RND_MASK;
00378     }
00379 
00380     return qof_numeric_convert (sum, denom, how);
00381 }

static QofNumeric qof_numeric_add_fixed ( QofNumeric  a,
QofNumeric  b 
) [inline, static]

Shortcut for common case: QofNumeric_add(a, b, QOF_DENOM_AUTO, QOF_HOW_DENOM_FIXED | QOF_HOW_RND_NEVER);

Definition at line 411 of file qofnumeric.h.

00412 {
00413     return qof_numeric_add (a, b, QOF_DENOM_AUTO,
00414                 QOF_HOW_DENOM_FIXED | QOF_HOW_RND_NEVER);
00415 }

QofNumeric qof_numeric_add_with_error ( QofNumeric  a,
QofNumeric  b,
gint64  denom,
gint  how,
QofNumeric error 
)

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

Definition at line 1014 of file qofnumeric.c.

01016 {
01017 
01018     QofNumeric sum = qof_numeric_add (a, b, denom, how);
01019     QofNumeric exact = qof_numeric_add (a, b, QOF_DENOM_AUTO,
01020         QOF_HOW_DENOM_REDUCE);
01021     QofNumeric err = qof_numeric_sub (sum, exact, QOF_DENOM_AUTO,
01022         QOF_HOW_DENOM_REDUCE);
01023 
01024     if (error)
01025         *error = err;
01026     return sum;
01027 }

QofNumericErrorCode qof_numeric_check ( QofNumeric  a  )  [inline]

Check for error signal in value. Returns QOF_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 44 of file qofnumeric.c.

00045 {
00046     if (in.denom != 0)
00047         return QOF_ERROR_OK;
00048     else if (in.num)
00049     {
00050         if ((0 < in.num) || (-4 > in.num))
00051             in.num = (gint64) QOF_ERROR_OVERFLOW;
00052         return (QofNumericErrorCode) in.num;
00053     }
00054     else
00055         return QOF_ERROR_ARG;
00056 }

gint qof_numeric_compare ( QofNumeric  a,
QofNumeric  b 
)

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

Definition at line 174 of file qofnumeric.c.

00175 {
00176     gint64 aa, bb;
00177     QofInt128 l, r;
00178 
00179     if (qof_numeric_check (a) || qof_numeric_check (b))
00180         return 0;
00181 
00182     if (a.denom == b.denom)
00183     {
00184         if (a.num == b.num)
00185             return 0;
00186         if (a.num > b.num)
00187             return 1;
00188         return -1;
00189     }
00190 
00191     if ((a.denom > 0) && (b.denom > 0))
00192     {
00193         /* Avoid overflows using 128-bit intermediate math */
00194         l = mult128 (a.num, b.denom);
00195         r = mult128 (b.num, a.denom);
00196         return cmp128 (l, r);
00197     }
00198 
00199     if (a.denom < 0)
00200         a.denom *= -1;
00201     if (b.denom < 0)
00202         b.denom *= -1;
00203 
00204     /* BUG: Possible overflow here..  Also, doesn't properly deal with
00205      * reciprocal denominators.
00206      */
00207     aa = a.num * a.denom;
00208     bb = b.num * b.denom;
00209 
00210     if (aa == bb)
00211         return 0;
00212     if (aa > bb)
00213         return 1;
00214     return -1;
00215 }

QofNumeric qof_numeric_convert ( QofNumeric  in,
gint64  denom,
gint  how 
)

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

Definition at line 662 of file qofnumeric.c.

00663 {
00664     QofNumeric out;
00665     QofNumeric temp;
00666     gint64 temp_bc;
00667     gint64 temp_a;
00668     gint64 remainder;
00669     gint64 sign;
00670     gint denom_neg = 0;
00671     gdouble ratio, logratio;
00672     gdouble sigfigs;
00673     QofInt128 nume, newm;
00674 
00675     temp.num = 0;
00676     temp.denom = 0;
00677 
00678     if (qof_numeric_check (in))
00679         return qof_numeric_error (QOF_ERROR_ARG);
00680 
00681     if (denom == QOF_DENOM_AUTO)
00682     {
00683         switch (how & QOF_NUMERIC_DENOM_MASK)
00684         {
00685         default:
00686         case QOF_HOW_DENOM_LCD: /* LCD is meaningless with AUTO in here */
00687         case QOF_HOW_DENOM_EXACT:
00688             return in;
00689             break;
00690 
00691         case QOF_HOW_DENOM_REDUCE:
00692             /* reduce the input to a relatively-prime fraction */
00693             return qof_numeric_reduce (in);
00694             break;
00695 
00696         case QOF_HOW_DENOM_FIXED:
00697             if (in.denom != denom)
00698                 return qof_numeric_error (QOF_ERROR_DENOM_DIFF);
00699             else
00700                 return in;
00701             break;
00702 
00703         case QOF_HOW_DENOM_SIGFIG:
00704             ratio = fabs (qof_numeric_to_double (in));
00705             if (ratio < 10e-20)
00706                 logratio = 0;
00707             else
00708             {
00709                 logratio = log10 (ratio);
00710                 logratio = ((logratio > 0.0) ?
00711                     (floor (logratio) + 1.0) : (ceil (logratio)));
00712             }
00713             sigfigs = QOF_HOW_GET_SIGFIGS (how);
00714 
00715             if (sigfigs - logratio >= 0)
00716                 denom = (gint64) (pow (10, sigfigs - logratio));
00717             else
00718                 denom = -((gint64) (pow (10, logratio - sigfigs)));
00719 
00720             how = how & ~QOF_HOW_DENOM_SIGFIG & ~QOF_NUMERIC_SIGFIGS_MASK;
00721             break;
00722         }
00723     }
00724 
00725     /* Make sure we need to do the work */
00726     if (in.denom == denom)
00727         return in;
00728     if (in.num == 0)
00729     {
00730         out.num = 0;
00731         out.denom = denom;
00732         return out;
00733     }
00734 
00735     /* If the denominator of the input value is negative, get rid of that. */
00736     if (in.denom < 0)
00737     {
00738         in.num = in.num * (-in.denom);  /* BUG: overflow not handled.  */
00739         in.denom = 1;
00740     }
00741 
00742     sign = (in.num < 0) ? -1 : 1;
00743 
00744     /* If the denominator is less than zero, we are to interpret it as 
00745      * the reciprocal of its magnitude. */
00746     if (denom < 0)
00747     {
00748 
00749         /* XXX FIXME: use 128-bit math here ... */
00750         denom = -denom;
00751         denom_neg = 1;
00752         temp_a = (in.num < 0) ? -in.num : in.num;
00753         temp_bc = in.denom * denom; /* BUG: overflow not handled.  */
00754         remainder = temp_a % temp_bc;
00755         out.num = temp_a / temp_bc;
00756         out.denom = -denom;
00757     }
00758     else
00759     {
00760         /* Do all the modulo and int division on positive values to make
00761          * things a little clearer. Reduce the fraction denom/in.denom to
00762          * help with range errors */
00763         temp.num = denom;
00764         temp.denom = in.denom;
00765         temp = qof_numeric_reduce (temp);
00766 
00767         /* Symbolically, do the following:
00768          * out.num   = in.num * temp.num;
00769          * remainder = out.num % temp.denom;
00770          * out.num   = out.num / temp.denom;
00771          * out.denom = denom;
00772          */
00773         nume = mult128 (in.num, temp.num);
00774         newm = div128 (nume, temp.denom);
00775         remainder = rem128 (nume, temp.denom);
00776 
00777         if (newm.isbig)
00778             return qof_numeric_error (QOF_ERROR_OVERFLOW);
00779 
00780         out.num = newm.lo;
00781         out.denom = denom;
00782     }
00783 
00784     if (remainder)
00785     {
00786         switch (how & QOF_NUMERIC_RND_MASK)
00787         {
00788         case QOF_HOW_RND_FLOOR:
00789             if (sign < 0)
00790                 out.num = out.num + 1;
00791             break;
00792 
00793         case QOF_HOW_RND_CEIL:
00794             if (sign > 0)
00795                 out.num = out.num + 1;
00796             break;
00797 
00798         case QOF_HOW_RND_TRUNC:
00799             break;
00800 
00801         case QOF_HOW_RND_PROMOTE:
00802             out.num = out.num + 1;
00803             break;
00804 
00805         case QOF_HOW_RND_ROUND_HALF_DOWN:
00806             if (denom_neg)
00807             {
00808                 if ((2 * remainder) > in.denom * denom)
00809                     out.num = out.num + 1;
00810                 }
00811             else if ((2 * remainder) > temp.denom)
00812                 out.num = out.num + 1;
00813             /* check that 2*remainder didn't over-flow */
00814             else if (((2 * remainder) < remainder) &&
00815                 (remainder > (temp.denom / 2)))
00816                 out.num = out.num + 1;
00817             break;
00818 
00819         case QOF_HOW_RND_ROUND_HALF_UP:
00820             if (denom_neg)
00821             {
00822                 if ((2 * remainder) >= in.denom * denom)
00823                     out.num = out.num + 1;
00824                 }
00825             else if ((2 * remainder) >= temp.denom)
00826                 out.num = out.num + 1;
00827             /* check that 2*remainder didn't over-flow */
00828             else if (((2 * remainder) < remainder) &&
00829                 (remainder >= (temp.denom / 2)))
00830                 out.num = out.num + 1;
00831             break;
00832 
00833         case QOF_HOW_RND_ROUND:
00834             if (denom_neg)
00835             {
00836                 if ((2 * remainder) > in.denom * denom)
00837                     out.num = out.num + 1;
00838                 else if ((2 * remainder) == in.denom * denom)
00839                 {
00840                     if (out.num % 2)
00841                         out.num = out.num + 1;
00842                     }
00843                 }
00844             else
00845             {
00846                 if ((2 * remainder) > temp.denom)
00847                     out.num = out.num + 1;
00848                 /* check that 2*remainder didn't over-flow */
00849                 else if (((2 * remainder) < remainder) &&
00850                     (remainder > (temp.denom / 2)))
00851                 {
00852                     out.num = out.num + 1;
00853                 }
00854                 else if ((2 * remainder) == temp.denom)
00855                 {
00856                     if (out.num % 2)
00857                         out.num = out.num + 1;
00858                     }
00859                 /* check that 2*remainder didn't over-flow */
00860                 else if (((2 * remainder) < remainder) &&
00861                     (remainder == (temp.denom / 2)))
00862                 {
00863                     if (out.num % 2)
00864                         out.num = out.num + 1;
00865                     }
00866                 }
00867             break;
00868 
00869         case QOF_HOW_RND_NEVER:
00870             return qof_numeric_error (QOF_ERROR_REMAINDER);
00871             break;
00872         }
00873     }
00874 
00875     out.num = (sign > 0) ? out.num : (-out.num);
00876 
00877     return out;
00878 }

QofNumeric qof_numeric_convert_with_error ( QofNumeric  in,
gint64  denom,
gint  how,
QofNumeric error 
)

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

static QofNumeric qof_numeric_create ( gint64  num,
gint64  denom 
) [inline, static]

Make a QofNumeric from numerator and denominator

Definition at line 243 of file qofnumeric.h.

00244 {
00245     QofNumeric out;
00246     out.num = num;
00247     out.denom = denom;
00248     return out;
00249 }

gchar* qof_numeric_dbg_to_string ( QofNumeric  n  ) 

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

Definition at line 1103 of file qofnumeric.c.

01104 {
01105     static gchar buff[1000];
01106     static gchar *p = buff;
01107     gint64 tmpnum = n.num;
01108     gint64 tmpdenom = n.denom;
01109 
01110     p += 100;
01111     if (p - buff >= 1000)
01112         p = buff;
01113 
01114     sprintf (p, "%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, tmpnum,
01115         tmpdenom);
01116 
01117     return p;
01118 }

static gint64 qof_numeric_denom ( QofNumeric  a  )  [inline, static]

Return denominator

Definition at line 291 of file qofnumeric.h.

00292 {
00293     return a.denom;
00294 }

QofNumeric qof_numeric_div ( QofNumeric  x,
QofNumeric  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 516 of file qofnumeric.c.

00517 {
00518     QofNumeric quotient;
00519     QofInt128 nume, deno;
00520 
00521     if (qof_numeric_check (a) || qof_numeric_check (b))
00522         return qof_numeric_error (QOF_ERROR_ARG);
00523 
00524     if ((denom == QOF_DENOM_AUTO) &&
00525         (how & QOF_NUMERIC_DENOM_MASK) == QOF_HOW_DENOM_FIXED)
00526     {
00527         if (a.denom == b.denom)
00528             denom = a.denom;
00529         else if (a.denom == 0)
00530             denom = b.denom;
00531         else
00532             return qof_numeric_error (QOF_ERROR_DENOM_DIFF);
00533         }
00534 
00535     if (a.denom < 0)
00536     {
00537         a.num *= -a.denom;      /* BUG: overflow not handled.  */
00538         a.denom = 1;
00539     }
00540 
00541     if (b.denom < 0)
00542     {
00543         b.num *= -b.denom;      /* BUG: overflow not handled.  */
00544         b.denom = 1;
00545     }
00546 
00547     if (a.denom == b.denom)
00548     {
00549         quotient.num = a.num;
00550         quotient.denom = b.num;
00551     }
00552     else
00553     {
00554         gint64 sgn = 1;
00555         if (0 > a.num)
00556         {
00557             sgn = -sgn;
00558             a.num = -a.num;
00559         }
00560         if (0 > b.num)
00561         {
00562             sgn = -sgn;
00563             b.num = -b.num;
00564         }
00565         nume = mult128 (a.num, b.denom);
00566         deno = mult128 (b.num, a.denom);
00567 
00568         /* Try to avoid overflow by removing common factors */
00569         if (nume.isbig && deno.isbig)
00570         {
00571             QofNumeric ra = qof_numeric_reduce (a);
00572             QofNumeric rb = qof_numeric_reduce (b);
00573             gint64 gcf_nume = gcf64 (ra.num, rb.num);
00574             gint64 gcf_deno = gcf64 (rb.denom, ra.denom);
00575 
00576             nume = mult128 (ra.num / gcf_nume, rb.denom / gcf_deno);
00577             deno = mult128 (rb.num / gcf_nume, ra.denom / gcf_deno);
00578         }
00579 
00580         if ((0 == nume.isbig) && (0 == deno.isbig))
00581         {
00582             quotient.num = sgn * nume.lo;
00583             quotient.denom = deno.lo;
00584             goto dive_done;
00585         }
00586         else if (0 == deno.isbig)
00587         {
00588             quotient = reduce128 (nume, deno.lo);
00589             if (0 == qof_numeric_check (quotient))
00590             {
00591                 quotient.num *= sgn;
00592                 goto dive_done;
00593             }
00594         }
00595 
00596         /* If rounding allowed, then shift until there's no 
00597          * more overflow. The conversion at the end will fix 
00598          * things up for the final value. */
00599         if ((how & QOF_NUMERIC_RND_MASK) == QOF_HOW_RND_NEVER)
00600             return qof_numeric_error (QOF_ERROR_OVERFLOW);
00601         while (nume.isbig || deno.isbig)
00602         {
00603             nume = shift128 (nume);
00604             deno = shift128 (deno);
00605         }
00606         quotient.num = sgn * nume.lo;
00607         quotient.denom = deno.lo;
00608         if (0 == quotient.denom)
00609         {
00610             return qof_numeric_error (QOF_ERROR_OVERFLOW);
00611         }
00612     }
00613 
00614     if (quotient.denom < 0)
00615     {
00616         quotient.num = -quotient.num;
00617         quotient.denom = -quotient.denom;
00618     }
00619 
00620   dive_done:
00621     if ((denom == QOF_DENOM_AUTO) &&
00622         ((how & QOF_NUMERIC_DENOM_MASK) == QOF_HOW_DENOM_LCD))
00623     {
00624         denom = qof_numeric_lcd (a, b);
00625         how = how & QOF_NUMERIC_RND_MASK;
00626     }
00627 
00628     return qof_numeric_convert (quotient, denom, how);
00629 }

QofNumeric qof_numeric_div_with_error ( QofNumeric  a,
QofNumeric  b,
gint64  denom,
gint  how,
QofNumeric error 
)

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

Definition at line 1071 of file qofnumeric.c.

01073 {
01074     QofNumeric quot = qof_numeric_div (a, b, denom, how);
01075     QofNumeric exact = qof_numeric_div (a, b, QOF_DENOM_AUTO,
01076         QOF_HOW_DENOM_REDUCE);
01077     QofNumeric err = qof_numeric_sub (quot, exact,
01078         QOF_DENOM_AUTO, QOF_HOW_DENOM_REDUCE);
01079     if (error)
01080         *error = err;
01081     return quot;
01082 }

gboolean qof_numeric_eq ( QofNumeric  a,
QofNumeric  b 
)

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

Definition at line 223 of file qofnumeric.c.

00224 {
00225     return ((a.num == b.num) && (a.denom == b.denom));
00226 }

gboolean qof_numeric_equal ( QofNumeric  a,
QofNumeric  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 233 of file qofnumeric.c.

00234 {
00235     QofInt128 l, r;
00236 
00237     if ((a.denom == b.denom) && (a.denom > 0))
00238         return (a.num == b.num);
00239     if ((a.denom > 0) && (b.denom > 0))
00240     {
00241         // return (a.num*b.denom == b.num*a.denom);
00242         l = mult128 (a.num, b.denom);
00243         r = mult128 (b.num, a.denom);
00244         return equal128 (l, r);
00245 
00246 #if ALT_WAY_OF_CHECKING_EQUALITY
00247         QofNumeric ra = QofNumeric_reduce (a);
00248         QofNumeric rb = QofNumeric_reduce (b);
00249         if (ra.denom != rb.denom)
00250             return 0;
00251         if (ra.num != rb.num)
00252             return 0;
00253         return 1;
00254 #endif
00255     }
00256     if ((a.denom < 0) && (b.denom < 0))
00257     {
00258         l = mult128 (a.num, -a.denom);
00259         r = mult128 (b.num, -b.denom);
00260         return equal128 (l, r);
00261     }
00262     else
00263     {
00264         /* BUG: One of the numbers has a reciprocal denom, and the other
00265            does not. I just don't know to handle this case in any
00266            reasonably overflow-proof yet simple way.  So, this funtion
00267            will simply get it wrong whenever the three multiplies
00268            overflow 64-bits.  -CAS */
00269         if (a.denom < 0)
00270             return ((a.num * -a.denom * b.denom) == b.num);
00271         else
00272             return (a.num == (b.num * a.denom * -b.denom));
00273         }
00274     return ((a.num * b.denom) == (a.denom * b.num));
00275 }

QofNumeric qof_numeric_error ( QofNumericErrorCode  error_code  ) 

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

Definition at line 1004 of file qofnumeric.c.

01005 {
01006     return qof_numeric_create (error_code, 0LL);
01007 }

QofNumeric qof_numeric_from_double ( gdouble  in,
gint64  denom,
gint  how 
)

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

Definition at line 919 of file qofnumeric.c.

00920 {
00921     QofNumeric out;
00922     gint64 int_part = 0;
00923     gdouble frac_part;
00924     gint64 frac_int = 0;
00925     gdouble logval;
00926     gdouble sigfigs;
00927 
00928     if ((denom == QOF_DENOM_AUTO) && (how & QOF_HOW_DENOM_SIGFIG))
00929     {
00930         if (fabs (in) < 10e-20)
00931             logval = 0;
00932         else
00933         {
00934             logval = log10 (fabs (in));
00935             logval = ((logval > 0.0) ?
00936                 (floor (logval) + 1.0) : (ceil (logval)));
00937         }
00938         sigfigs = QOF_HOW_GET_SIGFIGS (how);
00939         if (sigfigs - logval >= 0)
00940             denom = (gint64) (pow (10, sigfigs - logval));
00941         else
00942             denom = -((gint64) (pow (10, logval - sigfigs)));
00943 
00944         how = how & ~QOF_HOW_DENOM_SIGFIG & ~QOF_NUMERIC_SIGFIGS_MASK;
00945     }
00946 
00947     int_part = (gint64) (floor (fabs (in)));
00948     frac_part = in - (double) int_part;
00949 
00950     int_part = int_part * denom;
00951     frac_part = frac_part * (double) denom;
00952 
00953     switch (how & QOF_NUMERIC_RND_MASK)
00954     {
00955     case QOF_HOW_RND_FLOOR:
00956         frac_int = (gint64) floor (frac_part);
00957         break;
00958 
00959     case QOF_HOW_RND_CEIL:
00960         frac_int = (gint64) ceil (frac_part);
00961         break;
00962 
00963     case QOF_HOW_RND_TRUNC:
00964         frac_int = (gint64) frac_part;
00965         break;
00966 
00967     case QOF_HOW_RND_ROUND:
00968     case QOF_HOW_RND_ROUND_HALF_UP:
00969         frac_int = (gint64) rint (frac_part);
00970         break;
00971 
00972     case QOF_HOW_RND_NEVER:
00973         frac_int = (gint64) floor (frac_part);
00974         if (frac_part != (double) frac_int)
00975         {
00976             /* signal an error */
00977         }
00978         break;
00979     }
00980 
00981     out.num = int_part + frac_int;
00982     out.denom = denom;
00983     return out;
00984 }

gboolean qof_numeric_from_string ( const gchar *  str,
QofNumeric n 
)

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

Definition at line 1121 of file qofnumeric.c.

01122 {
01123     size_t num_read;
01124     gint64 tmpnum;
01125     gint64 tmpdenom;
01126 
01127     if (!str)
01128         return FALSE;
01129 
01130 #ifdef QOF_DEPRECATED
01131     /* must use "<" here because %n's effects aren't well defined */
01132     if (sscanf (str, " " QOF_SCANF_LLD "/" QOF_SCANF_LLD "%n",
01133             &tmpnum, &tmpdenom, &num_read) < 2)
01134     {
01135         return FALSE;
01136     }
01137 #else
01138     tmpnum = strtoll (str, NULL, 0);
01139     str = strchr (str, '/');
01140     if (!str)
01141         return FALSE;
01142     str++;
01143     tmpdenom = strtoll (str, NULL, 0);
01144     num_read = strspn (str, "0123456789");
01145 #endif
01146     n->num = tmpnum;
01147     n->denom = tmpdenom;
01148     return TRUE;
01149 }

QofNumeric qof_numeric_mul ( QofNumeric  a,
QofNumeric  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 405 of file qofnumeric.c.

00406 {
00407     QofNumeric product, result;
00408     QofInt128 bignume, bigdeno;
00409 
00410     if (qof_numeric_check (a) || qof_numeric_check (b))
00411         return qof_numeric_error (QOF_ERROR_ARG);
00412 
00413     if ((denom == QOF_DENOM_AUTO) &&
00414         (how & QOF_NUMERIC_DENOM_MASK) == QOF_HOW_DENOM_FIXED)
00415     {
00416         if (a.denom == b.denom)
00417             denom = a.denom;
00418         else if (b.num == 0)
00419             denom = a.denom;
00420         else if (a.num == 0)
00421             denom = b.denom;
00422         else
00423             return qof_numeric_error (QOF_ERROR_DENOM_DIFF);
00424     }
00425 
00426     if ((denom == QOF_DENOM_AUTO) &&
00427         ((how & QOF_NUMERIC_DENOM_MASK) == QOF_HOW_DENOM_LCD))
00428     {
00429         denom = qof_numeric_lcd (a, b);
00430         how = how & QOF_NUMERIC_RND_MASK;
00431     }
00432 
00433     if (a.denom < 0)
00434     {
00435         a.num *= -a.denom;      /* BUG: overflow not handled.  */
00436         a.denom = 1;
00437     }
00438 
00439     if (b.denom < 0)
00440     {
00441         b.num *= -b.denom;      /* BUG: overflow not handled.  */
00442         b.denom = 1;
00443     }
00444 
00445     bignume = mult128 (a.num, b.num);
00446     bigdeno = mult128 (a.denom, b.denom);
00447     product.num = a.num * b.num;
00448     product.denom = a.denom * b.denom;
00449 
00450     /* If it looks to be overflowing, try to reduce the fraction ... */
00451     if (bignume.isbig || bigdeno.isbig)
00452     {
00453         gint64 tmp;
00454 
00455         a = qof_numeric_reduce (a);
00456         b = qof_numeric_reduce (b);
00457         tmp = a.num;
00458         a.num = b.num;
00459         b.num = tmp;
00460         a = qof_numeric_reduce (a);
00461         b = qof_numeric_reduce (b);
00462         bignume = mult128 (a.num, b.num);
00463         bigdeno = mult128 (a.denom, b.denom);
00464         product.num = a.num * b.num;
00465         product.denom = a.denom * b.denom;
00466     }
00467 
00468     /* If it its still overflowing, and rounding is allowed then round */
00469     if (bignume.isbig || bigdeno.isbig)
00470     {
00471         /* If rounding allowed, then shift until there's no 
00472          * more overflow. The conversion at the end will fix 
00473          * things up for the final value. Else overflow. */
00474         if ((how & QOF_NUMERIC_RND_MASK) == QOF_HOW_RND_NEVER)
00475         {
00476             if (bigdeno.isbig)
00477                 return qof_numeric_error (QOF_ERROR_OVERFLOW);
00478             product = reduce128 (bignume, product.denom);
00479             if (qof_numeric_check (product))
00480                 return qof_numeric_error (QOF_ERROR_OVERFLOW);
00481         }
00482         else
00483         {
00484             while (bignume.isbig || bigdeno.isbig)
00485             {
00486                 bignume = shift128 (bignume);
00487                 bigdeno = shift128 (bigdeno);
00488             }
00489             product.num = bignume.lo;
00490             if (bignume.isneg)
00491                 product.num = -product.num;
00492 
00493             product.denom = bigdeno.lo;
00494             if (0 == product.denom)
00495                 return qof_numeric_error (QOF_ERROR_OVERFLOW);
00496         }
00497     }
00498 
00499 #if 0                           /* currently, product denom won't ever be zero */
00500     if (product.denom < 0)
00501     {
00502         product.num = -product.num;
00503         product.denom = -product.denom;
00504     }
00505 #endif
00506 
00507     result = qof_numeric_convert (product, denom, how);
00508     return result;
00509 }

QofNumeric qof_numeric_mul_with_error ( QofNumeric  a,
QofNumeric  b,
gint64  denom,
gint  how,
QofNumeric error 
)

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

Definition at line 1052 of file qofnumeric.c.

01054 {
01055     QofNumeric prod = qof_numeric_mul (a, b, denom, how);
01056     QofNumeric exact = qof_numeric_mul (a, b, QOF_DENOM_AUTO,
01057         QOF_HOW_DENOM_REDUCE);
01058     QofNumeric err = qof_numeric_sub (prod, exact, QOF_DENOM_AUTO,
01059         QOF_HOW_DENOM_REDUCE);
01060     if (error)
01061         *error = err;
01062     return prod;
01063 }

QofNumeric qof_numeric_neg ( QofNumeric  a  ) 

Negate the argument

Definition at line 637 of file qofnumeric.c.

00638 {
00639     if (qof_numeric_check (a))
00640         return qof_numeric_error (QOF_ERROR_ARG);
00641     return qof_numeric_create (-a.num, a.denom);
00642 }

gboolean qof_numeric_negative_p ( QofNumeric  a  ) 

Returns 1 if a < 0, otherwise returns 0.

Definition at line 137 of file qofnumeric.c.

00138 {
00139     if (qof_numeric_check (a))
00140         return 0;
00141     else
00142     {
00143         if ((a.num < 0) && (a.denom != 0))
00144             return 1;
00145         else
00146             return 0;
00147         }
00148 }

static gint64 qof_numeric_num ( QofNumeric  a  )  [inline, static]

Return numerator

Definition at line 284 of file qofnumeric.h.

00285 {
00286     return a.num;
00287 }

gboolean qof_numeric_positive_p ( QofNumeric  a  ) 

Returns 1 if a > 0, otherwise returns 0.

Definition at line 155 of file qofnumeric.c.

00156 {
00157     if (qof_numeric_check (a))
00158         return 0;
00159     else
00160     {
00161         if ((a.num > 0) && (a.denom != 0))
00162             return 1;
00163         else
00164             return 0;
00165         }
00166 }

QofNumeric qof_numeric_reduce ( QofNumeric  in  ) 

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

Definition at line 888 of file qofnumeric.c.

00889 {
00890     gint64 t;
00891     gint64 num = (in.num < 0) ? (-in.num) : in.num;
00892     gint64 denom = in.denom;
00893     QofNumeric out;
00894 
00895     if (qof_numeric_check (in))
00896         return qof_numeric_error (QOF_ERROR_ARG);
00897 
00898     /* The strategy is to use Euclid's algorithm */
00899     while (denom > 0)
00900     {
00901         t = num % denom;
00902         num = denom;
00903         denom = t;
00904     }
00905     /* num now holds the GCD (Greatest Common Divisor) */
00906 
00907     /* All calculations are done on positive num, since it's not 
00908      * well defined what % does for negative values */
00909     out.num = in.num / num;
00910     out.denom = in.denom / num;
00911     return out;
00912 }

gint qof_numeric_same ( QofNumeric  a,
QofNumeric  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 QofNumeric_equal.

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

Definition at line 285 of file qofnumeric.c.

00286 {
00287     QofNumeric aconv, bconv;
00288 
00289     aconv = qof_numeric_convert (a, denom, how);
00290     bconv = qof_numeric_convert (b, denom, how);
00291 
00292     return (qof_numeric_equal (aconv, bconv));
00293 }

QofNumeric qof_numeric_sub ( QofNumeric  a,
QofNumeric  b,
gint64  denom,
gint  how 
)

Return a-b.

Definition at line 388 of file qofnumeric.c.

00389 {
00390     QofNumeric nb;
00391 
00392     if (qof_numeric_check (a) || qof_numeric_check (b))
00393         return qof_numeric_error (QOF_ERROR_ARG);
00394 
00395     nb = b;
00396     nb.num = -nb.num;
00397     return qof_numeric_add (a, nb, denom, how);
00398 }

static QofNumeric qof_numeric_sub_fixed ( QofNumeric  a,
QofNumeric  b 
) [inline, static]

Shortcut for most common case: QofNumeric_sub(a, b, QOF_DENOM_AUTO, QOF_HOW_DENOM_FIXED | QOF_HOW_RND_NEVER);

Definition at line 422 of file qofnumeric.h.

00423 {
00424     return qof_numeric_sub (a, b, QOF_DENOM_AUTO,
00425                 QOF_HOW_DENOM_FIXED | QOF_HOW_RND_NEVER);
00426 }

QofNumeric qof_numeric_sub_with_error ( QofNumeric  a,
QofNumeric  b,
gint64  denom,
gint  how,
QofNumeric error 
)

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

Definition at line 1034 of file qofnumeric.c.

01036 {
01037     QofNumeric diff = qof_numeric_sub (a, b, denom, how);
01038     QofNumeric exact = qof_numeric_sub (a, b, QOF_DENOM_AUTO,
01039         QOF_HOW_DENOM_REDUCE);
01040     QofNumeric err = qof_numeric_sub (diff, exact, QOF_DENOM_AUTO,
01041         QOF_HOW_DENOM_REDUCE);
01042     if (error)
01043         *error = err;
01044     return diff;
01045 }

gdouble qof_numeric_to_double ( QofNumeric  in  ) 

Convert numeric to floating-point value.

Definition at line 991 of file qofnumeric.c.

00992 {
00993     if (in.denom > 0)
00994         return (gdouble) in.num / (gdouble) in.denom;
00995     else
00996         return (gdouble) (in.num * -in.denom);
00997 }

gchar* qof_numeric_to_string ( QofNumeric  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 1089 of file qofnumeric.c.

01090 {
01091     gchar *result;
01092     gint64 tmpnum = n.num;
01093     gint64 tmpdenom = n.denom;
01094 
01095     result =
01096         g_strdup_printf ("%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, tmpnum,
01097         tmpdenom);
01098 
01099     return result;
01100 }

static QofNumeric qof_numeric_zero ( void   )  [inline, static]

create a zero-value QofNumeric

Definition at line 253 of file qofnumeric.h.

00254 {
00255     return qof_numeric_create (0, 1);
00256 }

gboolean qof_numeric_zero_p ( QofNumeric  a  ) 

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

Definition at line 119 of file qofnumeric.c.

00120 {
00121     if (qof_numeric_check (a))
00122         return 0;
00123     else
00124     {
00125         if ((a.num == 0) && (a.denom != 0))
00126             return 1;
00127         else
00128             return 0;
00129         }
00130 }


Generated on Thu Jan 31 22:50:27 2008 for QOF by  doxygen 1.5.4