QOF  0.8.7
Modules | Files | Data Structures | Typedefs
Numeric: Rational Number Handling with Rounding Error Control

Modules

 Math128
 

Files

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

Data Structures

struct  _QofNumeric
 

Typedefs

typedef struct _QofNumeric QofNumeric
 A rational-number type. More...
 

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. More...
 
#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

Macro Definition 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)    (- ( 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)    ( ((( 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.

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.

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.

Function Documentation

QofNumeric qof_numeric_abs ( QofNumeric  a)

Return the absolute value of the argument

Definition at line 645 of file qofnumeric.c.

646 {
647  if (qof_numeric_check (a))
649  return qof_numeric_create (ABS (a.num), a.denom);
650 }
QofNumericErrorCode qof_numeric_check(QofNumeric in)
Definition: qofnumeric.c:39
QofNumeric qof_numeric_error(QofNumericErrorCode error_code)
Definition: qofnumeric.c:999
static QofNumeric qof_numeric_create(gint64 num, gint64 denom)
Definition: qofnumeric.h:243
QofNumeric qof_numeric_add ( QofNumeric  a,
QofNumeric  b,
gint64  denom,
gint  how 
)

Return a+b.

Definition at line 295 of file qofnumeric.c.

296 {
297  QofNumeric sum;
298 
299  if (qof_numeric_check (a) || qof_numeric_check (b))
301 
302  if ((denom == QOF_DENOM_AUTO) &&
303  (how & QOF_NUMERIC_DENOM_MASK) == QOF_HOW_DENOM_FIXED)
304  {
305  if (a.denom == b.denom)
306  denom = a.denom;
307  else if (b.num == 0)
308  {
309  denom = a.denom;
310  b.denom = a.denom;
311  }
312  else if (a.num == 0)
313  {
314  denom = b.denom;
315  a.denom = b.denom;
316  }
317  else
319  }
320 
321  if (a.denom < 0)
322  {
323  a.num *= -a.denom; /* BUG: overflow not handled. */
324  a.denom = 1;
325  }
326 
327  if (b.denom < 0)
328  {
329  b.num *= -b.denom; /* BUG: overflow not handled. */
330  b.denom = 1;
331  }
332 
333  /* Get an exact answer.. same denominator is the common case. */
334  if (a.denom == b.denom)
335  {
336  sum.num = a.num + b.num; /* BUG: overflow not handled. */
337  sum.denom = a.denom;
338  }
339  else
340  {
341  /* We want to do this:
342  * sum.num = a.num*b.denom + b.num*a.denom;
343  * sum.denom = a.denom*b.denom;
344  * but the multiply could overflow.
345  * Computing the LCD minimizes likelihood of overflow
346  */
347  gint64 lcd;
348  QofInt128 ca, cb, cab;
349 
350  lcd = qof_numeric_lcd (a, b);
351  if (QOF_ERROR_ARG == lcd)
353  ca = mult128 (a.num, lcd / a.denom);
354  if (ca.isbig)
356  cb = mult128 (b.num, lcd / b.denom);
357  if (cb.isbig)
359  cab = add128 (ca, cb);
360  if (cab.isbig)
362  sum.num = cab.lo;
363  if (cab.isneg)
364  sum.num = -sum.num;
365  sum.denom = lcd;
366  }
367 
368  if ((denom == QOF_DENOM_AUTO) &&
369  ((how & QOF_NUMERIC_DENOM_MASK) == QOF_HOW_DENOM_LCD))
370  {
371  denom = qof_numeric_lcd (a, b);
372  how = how & QOF_NUMERIC_RND_MASK;
373  }
374 
375  return qof_numeric_convert (sum, denom, how);
376 }
QofNumericErrorCode qof_numeric_check(QofNumeric in)
Definition: qofnumeric.c:39
gshort isneg
Definition: qofmath128.h:42
QofNumeric qof_numeric_error(QofNumericErrorCode error_code)
Definition: qofnumeric.c:999
#define QOF_NUMERIC_RND_MASK
bitmasks for HOW flags.
Definition: qofnumeric.h:116
QofInt128 add128(QofInt128 a, QofInt128 b)
Definition: qofmath128.c:308
QofNumeric qof_numeric_convert(QofNumeric in, gint64 denom, gint how)
Definition: qofnumeric.c:657
gshort isbig
Definition: qofmath128.h:43
QofInt128 mult128(gint64 a, gint64 b)
Definition: qofmath128.c:41
#define QOF_DENOM_AUTO
Definition: qofnumeric.h:231
static QofNumeric qof_numeric_add_fixed ( QofNumeric  a,
QofNumeric  b 
)
inlinestatic

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.

412 {
413  return qof_numeric_add (a, b, QOF_DENOM_AUTO,
415 }
QofNumeric qof_numeric_add(QofNumeric a, QofNumeric b, gint64 denom, gint how)
Definition: qofnumeric.c:295
#define QOF_DENOM_AUTO
Definition: qofnumeric.h:231
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.

1011 {
1012 
1013  QofNumeric sum = qof_numeric_add (a, b, denom, how);
1014  QofNumeric exact = qof_numeric_add (a, b, QOF_DENOM_AUTO,
1016  QofNumeric err = qof_numeric_sub (sum, exact, QOF_DENOM_AUTO,
1018 
1019  if (error)
1020  *error = err;
1021  return sum;
1022 }
QofNumeric qof_numeric_sub(QofNumeric a, QofNumeric b, gint64 denom, gint how)
Definition: qofnumeric.c:383
QofNumeric qof_numeric_add(QofNumeric a, QofNumeric b, gint64 denom, gint how)
Definition: qofnumeric.c:295
#define QOF_DENOM_AUTO
Definition: qofnumeric.h:231
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.

40 {
41  if (in.denom != 0)
42  return QOF_ERROR_OK;
43  else if (in.num)
44  {
45  if ((0 < in.num) || (-4 > in.num))
46  in.num = (gint64) QOF_ERROR_OVERFLOW;
47  return (QofNumericErrorCode) in.num;
48  }
49  else
50  return QOF_ERROR_ARG;
51 }
QofNumericErrorCode
Definition: qofnumeric.h:207
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.

170 {
171  gint64 aa, bb;
172  QofInt128 l, r;
173 
174  if (qof_numeric_check (a) || qof_numeric_check (b))
175  return 0;
176 
177  if (a.denom == b.denom)
178  {
179  if (a.num == b.num)
180  return 0;
181  if (a.num > b.num)
182  return 1;
183  return -1;
184  }
185 
186  if ((a.denom > 0) && (b.denom > 0))
187  {
188  /* Avoid overflows using 128-bit intermediate math */
189  l = mult128 (a.num, b.denom);
190  r = mult128 (b.num, a.denom);
191  return cmp128 (l, r);
192  }
193 
194  if (a.denom < 0)
195  a.denom *= -1;
196  if (b.denom < 0)
197  b.denom *= -1;
198 
199  /* BUG: Possible overflow here.. Also, doesn't properly deal with
200  * reciprocal denominators.
201  */
202  aa = a.num * a.denom;
203  bb = b.num * b.denom;
204 
205  if (aa == bb)
206  return 0;
207  if (aa > bb)
208  return 1;
209  return -1;
210 }
QofNumericErrorCode qof_numeric_check(QofNumeric in)
Definition: qofnumeric.c:39
gint cmp128(QofInt128 a, QofInt128 b)
Definition: qofmath128.c:246
QofInt128 mult128(gint64 a, gint64 b)
Definition: qofmath128.c:41
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.

658 {
659  QofNumeric out;
660  QofNumeric temp;
661  gint64 temp_bc;
662  gint64 temp_a;
663  gint64 remainder;
664  gint64 sign;
665  gint denom_neg = 0;
666  gdouble ratio, logratio;
667  gdouble sigfigs;
668  QofInt128 nume, newm;
669 
670  temp.num = 0;
671  temp.denom = 0;
672 
673  if (qof_numeric_check (in))
675 
676  if (denom == QOF_DENOM_AUTO)
677  {
678  switch (how & QOF_NUMERIC_DENOM_MASK)
679  {
680  default:
681  case QOF_HOW_DENOM_LCD: /* LCD is meaningless with AUTO in here */
682  case QOF_HOW_DENOM_EXACT:
683  return in;
684  break;
685 
687  /* reduce the input to a relatively-prime fraction */
688  return qof_numeric_reduce (in);
689  break;
690 
691  case QOF_HOW_DENOM_FIXED:
692  if (in.denom != denom)
694  else
695  return in;
696  break;
697 
699  ratio = fabs (qof_numeric_to_double (in));
700  if (ratio < 10e-20)
701  logratio = 0;
702  else
703  {
704  logratio = log10 (ratio);
705  logratio = ((logratio > 0.0) ?
706  (floor (logratio) + 1.0) : (ceil (logratio)));
707  }
708  sigfigs = QOF_HOW_GET_SIGFIGS (how);
709 
710  if (sigfigs - logratio >= 0)
711  denom = (gint64) (pow (10, sigfigs - logratio));
712  else
713  denom = -((gint64) (pow (10, logratio - sigfigs)));
714 
715  how = how & ~QOF_HOW_DENOM_SIGFIG & ~QOF_NUMERIC_SIGFIGS_MASK;
716  break;
717  }
718  }
719 
720  /* Make sure we need to do the work */
721  if (in.denom == denom)
722  return in;
723  if (in.num == 0)
724  {
725  out.num = 0;
726  out.denom = denom;
727  return out;
728  }
729 
730  /* If the denominator of the input value is negative, get rid of that. */
731  if (in.denom < 0)
732  {
733  in.num = in.num * (-in.denom); /* BUG: overflow not handled. */
734  in.denom = 1;
735  }
736 
737  sign = (in.num < 0) ? -1 : 1;
738 
739  /* If the denominator is less than zero, we are to interpret it as
740  * the reciprocal of its magnitude. */
741  if (denom < 0)
742  {
743 
744  /* XXX FIXME: use 128-bit math here ... */
745  denom = -denom;
746  denom_neg = 1;
747  temp_a = (in.num < 0) ? -in.num : in.num;
748  temp_bc = in.denom * denom; /* BUG: overflow not handled. */
749  remainder = temp_a % temp_bc;
750  out.num = temp_a / temp_bc;
751  out.denom = -denom;
752  }
753  else
754  {
755  /* Do all the modulo and int division on positive values to make
756  * things a little clearer. Reduce the fraction denom/in.denom to
757  * help with range errors */
758  temp.num = denom;
759  temp.denom = in.denom;
760  temp = qof_numeric_reduce (temp);
761 
762  /* Symbolically, do the following:
763  * out.num = in.num * temp.num;
764  * remainder = out.num % temp.denom;
765  * out.num = out.num / temp.denom;
766  * out.denom = denom;
767  */
768  nume = mult128 (in.num, temp.num);
769  newm = div128 (nume, temp.denom);
770  remainder = rem128 (nume, temp.denom);
771 
772  if (newm.isbig)
774 
775  out.num = newm.lo;
776  out.denom = denom;
777  }
778 
779  if (remainder)
780  {
781  switch (how & QOF_NUMERIC_RND_MASK)
782  {
783  case QOF_HOW_RND_FLOOR:
784  if (sign < 0)
785  out.num = out.num + 1;
786  break;
787 
788  case QOF_HOW_RND_CEIL:
789  if (sign > 0)
790  out.num = out.num + 1;
791  break;
792 
793  case QOF_HOW_RND_TRUNC:
794  break;
795 
796  case QOF_HOW_RND_PROMOTE:
797  out.num = out.num + 1;
798  break;
799 
801  if (denom_neg)
802  {
803  if ((2 * remainder) > in.denom * denom)
804  out.num = out.num + 1;
805  }
806  else if ((2 * remainder) > temp.denom)
807  out.num = out.num + 1;
808  /* check that 2*remainder didn't over-flow */
809  else if (((2 * remainder) < remainder) &&
810  (remainder > (temp.denom / 2)))
811  out.num = out.num + 1;
812  break;
813 
815  if (denom_neg)
816  {
817  if ((2 * remainder) >= in.denom * denom)
818  out.num = out.num + 1;
819  }
820  else if ((2 * remainder) >= temp.denom)
821  out.num = out.num + 1;
822  /* check that 2*remainder didn't over-flow */
823  else if (((2 * remainder) < remainder) &&
824  (remainder >= (temp.denom / 2)))
825  out.num = out.num + 1;
826  break;
827 
828  case QOF_HOW_RND_ROUND:
829  if (denom_neg)
830  {
831  if ((2 * remainder) > in.denom * denom)
832  out.num = out.num + 1;
833  else if ((2 * remainder) == in.denom * denom)
834  {
835  if (out.num % 2)
836  out.num = out.num + 1;
837  }
838  }
839  else
840  {
841  if ((2 * remainder) > temp.denom)
842  out.num = out.num + 1;
843  /* check that 2*remainder didn't over-flow */
844  else if (((2 * remainder) < remainder) &&
845  (remainder > (temp.denom / 2)))
846  {
847  out.num = out.num + 1;
848  }
849  else if ((2 * remainder) == temp.denom)
850  {
851  if (out.num % 2)
852  out.num = out.num + 1;
853  }
854  /* check that 2*remainder didn't over-flow */
855  else if (((2 * remainder) < remainder) &&
856  (remainder == (temp.denom / 2)))
857  {
858  if (out.num % 2)
859  out.num = out.num + 1;
860  }
861  }
862  break;
863 
864  case QOF_HOW_RND_NEVER:
866  break;
867  }
868  }
869 
870  out.num = (sign > 0) ? out.num : (-out.num);
871 
872  return out;
873 }
QofNumericErrorCode qof_numeric_check(QofNumeric in)
Definition: qofnumeric.c:39
QofNumeric qof_numeric_error(QofNumericErrorCode error_code)
Definition: qofnumeric.c:999
gint64 rem128(QofInt128 n, gint64 d)
Definition: qofmath128.c:220
gdouble qof_numeric_to_double(QofNumeric in)
Definition: qofnumeric.c:986
#define QOF_NUMERIC_RND_MASK
bitmasks for HOW flags.
Definition: qofnumeric.h:116
QofInt128 div128(QofInt128 n, gint64 d)
Definition: qofmath128.c:180
QofNumeric qof_numeric_reduce(QofNumeric in)
Definition: qofnumeric.c:883
gshort isbig
Definition: qofmath128.h:43
QofInt128 mult128(gint64 a, gint64 b)
Definition: qofmath128.c:41
#define QOF_DENOM_AUTO
Definition: qofnumeric.h:231
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 
)
inlinestatic

Make a QofNumeric from numerator and denominator

Definition at line 243 of file qofnumeric.h.

244 {
245  QofNumeric out;
246  out.num = num;
247  out.denom = denom;
248  return out;
249 }
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.

1099 {
1100  static gchar buff[1000];
1101  static gchar *p = buff;
1102  gint64 tmpnum = n.num;
1103  gint64 tmpdenom = n.denom;
1104 
1105  p += 100;
1106  if (p - buff >= 1000)
1107  p = buff;
1108 
1109  sprintf (p, "%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, tmpnum,
1110  tmpdenom);
1111 
1112  return p;
1113 }
static gint64 qof_numeric_denom ( QofNumeric  a)
inlinestatic

Return denominator

Definition at line 291 of file qofnumeric.h.

292 {
293  return a.denom;
294 }
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.

512 {
513  QofNumeric quotient;
514  QofInt128 nume, deno;
515 
516  if (qof_numeric_check (a) || qof_numeric_check (b))
518 
519  if ((denom == QOF_DENOM_AUTO) &&
520  (how & QOF_NUMERIC_DENOM_MASK) == QOF_HOW_DENOM_FIXED)
521  {
522  if (a.denom == b.denom)
523  denom = a.denom;
524  else if (a.denom == 0)
525  denom = b.denom;
526  else
528  }
529 
530  if (a.denom < 0)
531  {
532  a.num *= -a.denom; /* BUG: overflow not handled. */
533  a.denom = 1;
534  }
535 
536  if (b.denom < 0)
537  {
538  b.num *= -b.denom; /* BUG: overflow not handled. */
539  b.denom = 1;
540  }
541 
542  if (a.denom == b.denom)
543  {
544  quotient.num = a.num;
545  quotient.denom = b.num;
546  }
547  else
548  {
549  gint64 sgn = 1;
550  if (0 > a.num)
551  {
552  sgn = -sgn;
553  a.num = -a.num;
554  }
555  if (0 > b.num)
556  {
557  sgn = -sgn;
558  b.num = -b.num;
559  }
560  nume = mult128 (a.num, b.denom);
561  deno = mult128 (b.num, a.denom);
562 
563  /* Try to avoid overflow by removing common factors */
564  if (nume.isbig && deno.isbig)
565  {
568  gint64 gcf_nume = gcf64 (ra.num, rb.num);
569  gint64 gcf_deno = gcf64 (rb.denom, ra.denom);
570 
571  nume = mult128 (ra.num / gcf_nume, rb.denom / gcf_deno);
572  deno = mult128 (rb.num / gcf_nume, ra.denom / gcf_deno);
573  }
574 
575  if ((0 == nume.isbig) && (0 == deno.isbig))
576  {
577  quotient.num = sgn * nume.lo;
578  quotient.denom = deno.lo;
579  goto dive_done;
580  }
581  else if (0 == deno.isbig)
582  {
583  quotient = reduce128 (nume, deno.lo);
584  if (0 == qof_numeric_check (quotient))
585  {
586  quotient.num *= sgn;
587  goto dive_done;
588  }
589  }
590 
591  /* If rounding allowed, then shift until there's no
592  * more overflow. The conversion at the end will fix
593  * things up for the final value. */
596  while (nume.isbig || deno.isbig)
597  {
598  nume = shift128 (nume);
599  deno = shift128 (deno);
600  }
601  quotient.num = sgn * nume.lo;
602  quotient.denom = deno.lo;
603  if (0 == quotient.denom)
604  {
606  }
607  }
608 
609  if (quotient.denom < 0)
610  {
611  quotient.num = -quotient.num;
612  quotient.denom = -quotient.denom;
613  }
614 
615  dive_done:
616  if ((denom == QOF_DENOM_AUTO) &&
617  ((how & QOF_NUMERIC_DENOM_MASK) == QOF_HOW_DENOM_LCD))
618  {
619  denom = qof_numeric_lcd (a, b);
620  how = how & QOF_NUMERIC_RND_MASK;
621  }
622 
623  return qof_numeric_convert (quotient, denom, how);
624 }
guint64 gcf64(guint64 num, guint64 denom)
Definition: qofmath128.c:278
QofNumericErrorCode qof_numeric_check(QofNumeric in)
Definition: qofnumeric.c:39
QofNumeric qof_numeric_error(QofNumericErrorCode error_code)
Definition: qofnumeric.c:999
#define QOF_NUMERIC_RND_MASK
bitmasks for HOW flags.
Definition: qofnumeric.h:116
QofInt128 shift128(QofInt128 x)
Definition: qofmath128.c:110
QofNumeric qof_numeric_reduce(QofNumeric in)
Definition: qofnumeric.c:883
QofNumeric qof_numeric_convert(QofNumeric in, gint64 denom, gint how)
Definition: qofnumeric.c:657
gshort isbig
Definition: qofmath128.h:43
QofInt128 mult128(gint64 a, gint64 b)
Definition: qofmath128.c:41
#define QOF_DENOM_AUTO
Definition: qofnumeric.h:231
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.

1068 {
1069  QofNumeric quot = qof_numeric_div (a, b, denom, how);
1070  QofNumeric exact = qof_numeric_div (a, b, QOF_DENOM_AUTO,
1072  QofNumeric err = qof_numeric_sub (quot, exact,
1074  if (error)
1075  *error = err;
1076  return quot;
1077 }
QofNumeric qof_numeric_sub(QofNumeric a, QofNumeric b, gint64 denom, gint how)
Definition: qofnumeric.c:383
QofNumeric qof_numeric_div(QofNumeric a, QofNumeric b, gint64 denom, gint how)
Definition: qofnumeric.c:511
#define QOF_DENOM_AUTO
Definition: qofnumeric.h:231
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.

219 {
220  return ((a.num == b.num) && (a.denom == b.denom));
221 }
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.

229 {
230  QofInt128 l, r;
231 
232  if ((a.denom == b.denom) && (a.denom > 0))
233  return (a.num == b.num);
234  if ((a.denom > 0) && (b.denom > 0))
235  {
236  // return (a.num*b.denom == b.num*a.denom);
237  l = mult128 (a.num, b.denom);
238  r = mult128 (b.num, a.denom);
239  return equal128 (l, r);
240 
241 #if ALT_WAY_OF_CHECKING_EQUALITY
242  QofNumeric ra = QofNumeric_reduce (a);
243  QofNumeric rb = QofNumeric_reduce (b);
244  if (ra.denom != rb.denom)
245  return 0;
246  if (ra.num != rb.num)
247  return 0;
248  return 1;
249 #endif
250  }
251  if ((a.denom < 0) && (b.denom < 0))
252  {
253  l = mult128 (a.num, -a.denom);
254  r = mult128 (b.num, -b.denom);
255  return equal128 (l, r);
256  }
257  else
258  {
259  /* BUG: One of the numbers has a reciprocal denom, and the other
260  does not. I just don't know to handle this case in any
261  reasonably overflow-proof yet simple way. So, this funtion
262  will simply get it wrong whenever the three multiplies
263  overflow 64-bits. -CAS */
264  if (a.denom < 0)
265  return ((a.num * -a.denom * b.denom) == b.num);
266  else
267  return (a.num == (b.num * a.denom * -b.denom));
268  }
269  return ((a.num * b.denom) == (a.denom * b.num));
270 }
gboolean equal128(QofInt128 a, QofInt128 b)
Definition: qofmath128.c:233
QofInt128 mult128(gint64 a, gint64 b)
Definition: qofmath128.c:41
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.

1000 {
1001  return qof_numeric_create (error_code, 0LL);
1002 }
static QofNumeric qof_numeric_create(gint64 num, gint64 denom)
Definition: qofnumeric.h:243
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.

915 {
916  QofNumeric out;
917  gint64 int_part = 0;
918  gdouble frac_part;
919  gint64 frac_int = 0;
920  gdouble logval;
921  gdouble sigfigs;
922 
923  if ((denom == QOF_DENOM_AUTO) && (how & QOF_HOW_DENOM_SIGFIG))
924  {
925  if (fabs (in) < 10e-20)
926  logval = 0;
927  else
928  {
929  logval = log10 (fabs (in));
930  logval = ((logval > 0.0) ?
931  (floor (logval) + 1.0) : (ceil (logval)));
932  }
933  sigfigs = QOF_HOW_GET_SIGFIGS (how);
934  if (sigfigs - logval >= 0)
935  denom = (gint64) (pow (10, sigfigs - logval));
936  else
937  denom = -((gint64) (pow (10, logval - sigfigs)));
938 
939  how = how & ~QOF_HOW_DENOM_SIGFIG & ~QOF_NUMERIC_SIGFIGS_MASK;
940  }
941 
942  int_part = (gint64) (floor (fabs (in)));
943  frac_part = in - (double) int_part;
944 
945  int_part = int_part * denom;
946  frac_part = frac_part * (double) denom;
947 
948  switch (how & QOF_NUMERIC_RND_MASK)
949  {
950  case QOF_HOW_RND_FLOOR:
951  frac_int = (gint64) floor (frac_part);
952  break;
953 
954  case QOF_HOW_RND_CEIL:
955  frac_int = (gint64) ceil (frac_part);
956  break;
957 
958  case QOF_HOW_RND_TRUNC:
959  frac_int = (gint64) frac_part;
960  break;
961 
962  case QOF_HOW_RND_ROUND:
964  frac_int = (gint64) rint (frac_part);
965  break;
966 
967  case QOF_HOW_RND_NEVER:
968  frac_int = (gint64) floor (frac_part);
969  if (frac_part != (double) frac_int)
970  {
971  /* signal an error */
972  }
973  break;
974  }
975 
976  out.num = int_part + frac_int;
977  out.denom = denom;
978  return out;
979 }
#define QOF_NUMERIC_RND_MASK
bitmasks for HOW flags.
Definition: qofnumeric.h:116
#define QOF_DENOM_AUTO
Definition: qofnumeric.h:231
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.

1117 {
1118  size_t G_GNUC_UNUSED num_read;
1119  gint64 tmpnum;
1120  gint64 tmpdenom;
1121 
1122  if (!str)
1123  return FALSE;
1124  tmpnum = strtoll (str, NULL, 0);
1125  str = strchr (str, '/');
1126  if (!str)
1127  return FALSE;
1128  str++;
1129  tmpdenom = strtoll (str, NULL, 0);
1130  num_read = strspn (str, "0123456789");
1131  n->num = tmpnum;
1132  n->denom = tmpdenom;
1133  return TRUE;
1134 }
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.

401 {
402  QofNumeric product, result;
403  QofInt128 bignume, bigdeno;
404 
405  if (qof_numeric_check (a) || qof_numeric_check (b))
407 
408  if ((denom == QOF_DENOM_AUTO) &&
409  (how & QOF_NUMERIC_DENOM_MASK) == QOF_HOW_DENOM_FIXED)
410  {
411  if (a.denom == b.denom)
412  denom = a.denom;
413  else if (b.num == 0)
414  denom = a.denom;
415  else if (a.num == 0)
416  denom = b.denom;
417  else
419  }
420 
421  if ((denom == QOF_DENOM_AUTO) &&
422  ((how & QOF_NUMERIC_DENOM_MASK) == QOF_HOW_DENOM_LCD))
423  {
424  denom = qof_numeric_lcd (a, b);
425  how = how & QOF_NUMERIC_RND_MASK;
426  }
427 
428  if (a.denom < 0)
429  {
430  a.num *= -a.denom; /* BUG: overflow not handled. */
431  a.denom = 1;
432  }
433 
434  if (b.denom < 0)
435  {
436  b.num *= -b.denom; /* BUG: overflow not handled. */
437  b.denom = 1;
438  }
439 
440  bignume = mult128 (a.num, b.num);
441  bigdeno = mult128 (a.denom, b.denom);
442  product.num = a.num * b.num;
443  product.denom = a.denom * b.denom;
444 
445  /* If it looks to be overflowing, try to reduce the fraction ... */
446  if (bignume.isbig || bigdeno.isbig)
447  {
448  gint64 tmp;
449 
450  a = qof_numeric_reduce (a);
451  b = qof_numeric_reduce (b);
452  tmp = a.num;
453  a.num = b.num;
454  b.num = tmp;
455  a = qof_numeric_reduce (a);
456  b = qof_numeric_reduce (b);
457  bignume = mult128 (a.num, b.num);
458  bigdeno = mult128 (a.denom, b.denom);
459  product.num = a.num * b.num;
460  product.denom = a.denom * b.denom;
461  }
462 
463  /* If it its still overflowing, and rounding is allowed then round */
464  if (bignume.isbig || bigdeno.isbig)
465  {
466  /* If rounding allowed, then shift until there's no
467  * more overflow. The conversion at the end will fix
468  * things up for the final value. Else overflow. */
470  {
471  if (bigdeno.isbig)
473  product = reduce128 (bignume, product.denom);
474  if (qof_numeric_check (product))
476  }
477  else
478  {
479  while (bignume.isbig || bigdeno.isbig)
480  {
481  bignume = shift128 (bignume);
482  bigdeno = shift128 (bigdeno);
483  }
484  product.num = bignume.lo;
485  if (bignume.isneg)
486  product.num = -product.num;
487 
488  product.denom = bigdeno.lo;
489  if (0 == product.denom)
491  }
492  }
493 
494 #if 0 /* currently, product denom won't ever be zero */
495  if (product.denom < 0)
496  {
497  product.num = -product.num;
498  product.denom = -product.denom;
499  }
500 #endif
501 
502  result = qof_numeric_convert (product, denom, how);
503  return result;
504 }
QofNumericErrorCode qof_numeric_check(QofNumeric in)
Definition: qofnumeric.c:39
gshort isneg
Definition: qofmath128.h:42
QofNumeric qof_numeric_error(QofNumericErrorCode error_code)
Definition: qofnumeric.c:999
#define QOF_NUMERIC_RND_MASK
bitmasks for HOW flags.
Definition: qofnumeric.h:116
QofInt128 shift128(QofInt128 x)
Definition: qofmath128.c:110
QofNumeric qof_numeric_reduce(QofNumeric in)
Definition: qofnumeric.c:883
QofNumeric qof_numeric_convert(QofNumeric in, gint64 denom, gint how)
Definition: qofnumeric.c:657
gshort isbig
Definition: qofmath128.h:43
QofInt128 mult128(gint64 a, gint64 b)
Definition: qofmath128.c:41
#define QOF_DENOM_AUTO
Definition: qofnumeric.h:231
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.

1049 {
1050  QofNumeric prod = qof_numeric_mul (a, b, denom, how);
1051  QofNumeric exact = qof_numeric_mul (a, b, QOF_DENOM_AUTO,
1053  QofNumeric err = qof_numeric_sub (prod, exact, QOF_DENOM_AUTO,
1055  if (error)
1056  *error = err;
1057  return prod;
1058 }
QofNumeric qof_numeric_mul(QofNumeric a, QofNumeric b, gint64 denom, gint how)
Definition: qofnumeric.c:400
QofNumeric qof_numeric_sub(QofNumeric a, QofNumeric b, gint64 denom, gint how)
Definition: qofnumeric.c:383
#define QOF_DENOM_AUTO
Definition: qofnumeric.h:231
QofNumeric qof_numeric_neg ( QofNumeric  a)

Negate the argument

Definition at line 632 of file qofnumeric.c.

633 {
634  if (qof_numeric_check (a))
636  return qof_numeric_create (-a.num, a.denom);
637 }
QofNumericErrorCode qof_numeric_check(QofNumeric in)
Definition: qofnumeric.c:39
QofNumeric qof_numeric_error(QofNumericErrorCode error_code)
Definition: qofnumeric.c:999
static QofNumeric qof_numeric_create(gint64 num, gint64 denom)
Definition: qofnumeric.h:243
gboolean qof_numeric_negative_p ( QofNumeric  a)

Returns 1 if a < 0, otherwise returns 0.

Definition at line 132 of file qofnumeric.c.

133 {
134  if (qof_numeric_check (a))
135  return 0;
136  else
137  {
138  if ((a.num < 0) && (a.denom != 0))
139  return 1;
140  else
141  return 0;
142  }
143 }
QofNumericErrorCode qof_numeric_check(QofNumeric in)
Definition: qofnumeric.c:39
static gint64 qof_numeric_num ( QofNumeric  a)
inlinestatic

Return numerator

Definition at line 284 of file qofnumeric.h.

285 {
286  return a.num;
287 }
gboolean qof_numeric_positive_p ( QofNumeric  a)

Returns 1 if a > 0, otherwise returns 0.

Definition at line 150 of file qofnumeric.c.

151 {
152  if (qof_numeric_check (a))
153  return 0;
154  else
155  {
156  if ((a.num > 0) && (a.denom != 0))
157  return 1;
158  else
159  return 0;
160  }
161 }
QofNumericErrorCode qof_numeric_check(QofNumeric in)
Definition: qofnumeric.c:39
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.

884 {
885  gint64 t;
886  gint64 num = (in.num < 0) ? (-in.num) : in.num;
887  gint64 denom = in.denom;
888  QofNumeric out;
889 
890  if (qof_numeric_check (in))
892 
893  /* The strategy is to use Euclid's algorithm */
894  while (denom > 0)
895  {
896  t = num % denom;
897  num = denom;
898  denom = t;
899  }
900  /* num now holds the GCD (Greatest Common Divisor) */
901 
902  /* All calculations are done on positive num, since it's not
903  * well defined what % does for negative values */
904  out.num = in.num / num;
905  out.denom = in.denom / num;
906  return out;
907 }
QofNumericErrorCode qof_numeric_check(QofNumeric in)
Definition: qofnumeric.c:39
QofNumeric qof_numeric_error(QofNumericErrorCode error_code)
Definition: qofnumeric.c:999
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.

281 {
282  QofNumeric aconv, bconv;
283 
284  aconv = qof_numeric_convert (a, denom, how);
285  bconv = qof_numeric_convert (b, denom, how);
286 
287  return (qof_numeric_equal (aconv, bconv));
288 }
gboolean qof_numeric_equal(QofNumeric a, QofNumeric b)
Definition: qofnumeric.c:228
QofNumeric qof_numeric_convert(QofNumeric in, gint64 denom, gint how)
Definition: qofnumeric.c:657
QofNumeric qof_numeric_sub ( QofNumeric  a,
QofNumeric  b,
gint64  denom,
gint  how 
)

Return a-b.

Definition at line 383 of file qofnumeric.c.

384 {
385  QofNumeric nb;
386 
387  if (qof_numeric_check (a) || qof_numeric_check (b))
389 
390  nb = b;
391  nb.num = -nb.num;
392  return qof_numeric_add (a, nb, denom, how);
393 }
QofNumericErrorCode qof_numeric_check(QofNumeric in)
Definition: qofnumeric.c:39
QofNumeric qof_numeric_error(QofNumericErrorCode error_code)
Definition: qofnumeric.c:999
QofNumeric qof_numeric_add(QofNumeric a, QofNumeric b, gint64 denom, gint how)
Definition: qofnumeric.c:295
static QofNumeric qof_numeric_sub_fixed ( QofNumeric  a,
QofNumeric  b 
)
inlinestatic

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.

423 {
424  return qof_numeric_sub (a, b, QOF_DENOM_AUTO,
426 }
QofNumeric qof_numeric_sub(QofNumeric a, QofNumeric b, gint64 denom, gint how)
Definition: qofnumeric.c:383
#define QOF_DENOM_AUTO
Definition: qofnumeric.h:231
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.

1031 {
1032  QofNumeric diff = qof_numeric_sub (a, b, denom, how);
1033  QofNumeric exact = qof_numeric_sub (a, b, QOF_DENOM_AUTO,
1035  QofNumeric err = qof_numeric_sub (diff, exact, QOF_DENOM_AUTO,
1037  if (error)
1038  *error = err;
1039  return diff;
1040 }
QofNumeric qof_numeric_sub(QofNumeric a, QofNumeric b, gint64 denom, gint how)
Definition: qofnumeric.c:383
#define QOF_DENOM_AUTO
Definition: qofnumeric.h:231
gdouble qof_numeric_to_double ( QofNumeric  in)

Convert numeric to floating-point value.

Definition at line 986 of file qofnumeric.c.

987 {
988  if (in.denom > 0)
989  return (gdouble) in.num / (gdouble) in.denom;
990  else
991  return (gdouble) (in.num * -in.denom);
992 }
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.

1085 {
1086  gchar *result;
1087  gint64 tmpnum = n.num;
1088  gint64 tmpdenom = n.denom;
1089 
1090  result =
1091  g_strdup_printf ("%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, tmpnum,
1092  tmpdenom);
1093 
1094  return result;
1095 }
static QofNumeric qof_numeric_zero ( void  )
inlinestatic

create a zero-value QofNumeric

Definition at line 253 of file qofnumeric.h.

254 {
255  return qof_numeric_create (0, 1);
256 }
static QofNumeric qof_numeric_create(gint64 num, gint64 denom)
Definition: qofnumeric.h:243
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.

115 {
116  if (qof_numeric_check (a))
117  return 0;
118  else
119  {
120  if ((a.num == 0) && (a.denom != 0))
121  return 1;
122  else
123  return 0;
124  }
125 }
QofNumericErrorCode qof_numeric_check(QofNumeric in)
Definition: qofnumeric.c:39