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) |
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.
#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 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.
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:
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.
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
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;
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] |
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.
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] |
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 }