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


Data Structures

struct  _QofNumeric

Modules

 Math128

Files

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

Typedefs

typedef struct _QofNumeric QofNumeric
 A rational-number type.

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)

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


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 };

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 645 of file qofnumeric.c.

00646 {
00647     if (qof_numeric_check (a))
00648         return qof_numeric_error (QOF_ERROR_ARG);
00649     return qof_numeric_create (ABS (a.num), a.denom);
00650 }

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

Return a+b.

Definition at line 295 of file qofnumeric.c.

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

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 1009 of file qofnumeric.c.

01011 {
01012 
01013     QofNumeric sum = qof_numeric_add (a, b, denom, how);
01014     QofNumeric exact = qof_numeric_add (a, b, QOF_DENOM_AUTO,
01015         QOF_HOW_DENOM_REDUCE);
01016     QofNumeric err = qof_numeric_sub (sum, exact, QOF_DENOM_AUTO,
01017         QOF_HOW_DENOM_REDUCE);
01018 
01019     if (error)
01020         *error = err;
01021     return sum;
01022 }

QofNumericErrorCode qof_numeric_check ( QofNumeric  a  ) 

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 39 of file qofnumeric.c.

00040 {
00041     if (in.denom != 0)
00042         return QOF_ERROR_OK;
00043     else if (in.num)
00044     {
00045         if ((0 < in.num) || (-4 > in.num))
00046             in.num = (gint64) QOF_ERROR_OVERFLOW;
00047         return (QofNumericErrorCode) in.num;
00048     }
00049     else
00050         return QOF_ERROR_ARG;
00051 }

gint qof_numeric_compare ( QofNumeric  a,
QofNumeric  b 
)

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

Definition at line 169 of file qofnumeric.c.

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

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 657 of file qofnumeric.c.

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

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 1098 of file qofnumeric.c.

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

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 511 of file qofnumeric.c.

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

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 1066 of file qofnumeric.c.

01068 {
01069     QofNumeric quot = qof_numeric_div (a, b, denom, how);
01070     QofNumeric exact = qof_numeric_div (a, b, QOF_DENOM_AUTO,
01071         QOF_HOW_DENOM_REDUCE);
01072     QofNumeric err = qof_numeric_sub (quot, exact,
01073         QOF_DENOM_AUTO, QOF_HOW_DENOM_REDUCE);
01074     if (error)
01075         *error = err;
01076     return quot;
01077 }

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 218 of file qofnumeric.c.

00219 {
00220     return ((a.num == b.num) && (a.denom == b.denom));
00221 }

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 228 of file qofnumeric.c.

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

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 999 of file qofnumeric.c.

01000 {
01001     return qof_numeric_create (error_code, 0LL);
01002 }

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 914 of file qofnumeric.c.

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

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 1116 of file qofnumeric.c.

01117 {
01118     size_t num_read;
01119     gint64 tmpnum;
01120     gint64 tmpdenom;
01121 
01122     if (!str)
01123         return FALSE;
01124     tmpnum = strtoll (str, NULL, 0);
01125     str = strchr (str, '/');
01126     if (!str)
01127         return FALSE;
01128     str++;
01129     tmpdenom = strtoll (str, NULL, 0);
01130     num_read = strspn (str, "0123456789");
01131     n->num = tmpnum;
01132     n->denom = tmpdenom;
01133     return TRUE;
01134 }

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 400 of file qofnumeric.c.

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

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 1047 of file qofnumeric.c.

01049 {
01050     QofNumeric prod = qof_numeric_mul (a, b, denom, how);
01051     QofNumeric exact = qof_numeric_mul (a, b, QOF_DENOM_AUTO,
01052         QOF_HOW_DENOM_REDUCE);
01053     QofNumeric err = qof_numeric_sub (prod, exact, QOF_DENOM_AUTO,
01054         QOF_HOW_DENOM_REDUCE);
01055     if (error)
01056         *error = err;
01057     return prod;
01058 }

QofNumeric qof_numeric_neg ( QofNumeric  a  ) 

Negate the argument

Definition at line 632 of file qofnumeric.c.

00633 {
00634     if (qof_numeric_check (a))
00635         return qof_numeric_error (QOF_ERROR_ARG);
00636     return qof_numeric_create (-a.num, a.denom);
00637 }

gboolean qof_numeric_negative_p ( QofNumeric  a  ) 

Returns 1 if a < 0, otherwise returns 0.

Definition at line 132 of file qofnumeric.c.

00133 {
00134     if (qof_numeric_check (a))
00135         return 0;
00136     else
00137     {
00138         if ((a.num < 0) && (a.denom != 0))
00139             return 1;
00140         else
00141             return 0;
00142         }
00143 }

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 150 of file qofnumeric.c.

00151 {
00152     if (qof_numeric_check (a))
00153         return 0;
00154     else
00155     {
00156         if ((a.num > 0) && (a.denom != 0))
00157             return 1;
00158         else
00159             return 0;
00160         }
00161 }

QofNumeric qof_numeric_reduce ( QofNumeric  in  ) 

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

Definition at line 883 of file qofnumeric.c.

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

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 280 of file qofnumeric.c.

00281 {
00282     QofNumeric aconv, bconv;
00283 
00284     aconv = qof_numeric_convert (a, denom, how);
00285     bconv = qof_numeric_convert (b, denom, how);
00286 
00287     return (qof_numeric_equal (aconv, bconv));
00288 }

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

Return a-b.

Definition at line 383 of file qofnumeric.c.

00384 {
00385     QofNumeric nb;
00386 
00387     if (qof_numeric_check (a) || qof_numeric_check (b))
00388         return qof_numeric_error (QOF_ERROR_ARG);
00389 
00390     nb = b;
00391     nb.num = -nb.num;
00392     return qof_numeric_add (a, nb, denom, how);
00393 }

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 1029 of file qofnumeric.c.

01031 {
01032     QofNumeric diff = qof_numeric_sub (a, b, denom, how);
01033     QofNumeric exact = qof_numeric_sub (a, b, QOF_DENOM_AUTO,
01034         QOF_HOW_DENOM_REDUCE);
01035     QofNumeric err = qof_numeric_sub (diff, exact, QOF_DENOM_AUTO,
01036         QOF_HOW_DENOM_REDUCE);
01037     if (error)
01038         *error = err;
01039     return diff;
01040 }

gdouble qof_numeric_to_double ( QofNumeric  in  ) 

Convert numeric to floating-point value.

Definition at line 986 of file qofnumeric.c.

00987 {
00988     if (in.denom > 0)
00989         return (gdouble) in.num / (gdouble) in.denom;
00990     else
00991         return (gdouble) (in.num * -in.denom);
00992 }

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 1084 of file qofnumeric.c.

01085 {
01086     gchar *result;
01087     gint64 tmpnum = n.num;
01088     gint64 tmpdenom = n.denom;
01089 
01090     result =
01091         g_strdup_printf ("%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, tmpnum,
01092         tmpdenom);
01093 
01094     return result;
01095 }

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 114 of file qofnumeric.c.

00115 {
00116     if (qof_numeric_check (a))
00117         return 0;
00118     else
00119     {
00120         if ((a.num == 0) && (a.denom != 0))
00121             return 1;
00122         else
00123             return 0;
00124         }
00125 }


Generated on Mon Jul 13 05:15:22 2009 for QOF by  doxygen 1.5.9