QOF: Numeric: Rational Number Handling with Rounding Error Control

QOF 0.7.5

Modules | Files | Data Structures | Typedefs
Numeric: Rational Number Handling with Rounding Error Control
Query Object Framework

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

## ◆ QOF_DENOM_AUTO

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

## ◆ QOF_DENOM_RECIPROCAL

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

## ◆ QOF_HOW_DENOM_SIGFIGS

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

## ◆ QOF_NUMERIC_RND_MASK

#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

## ◆ QofNumeric

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

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.

130 {
132 QOF_HOW_RND_FLOOR = 0x01,
133
135 QOF_HOW_RND_CEIL = 0x02,
136
138 QOF_HOW_RND_TRUNC = 0x03,
139
141 QOF_HOW_RND_PROMOTE = 0x04,
142
146 QOF_HOW_RND_ROUND_HALF_DOWN = 0x05,
147
151 QOF_HOW_RND_ROUND_HALF_UP = 0x06,
152
158 QOF_HOW_RND_ROUND = 0x07,
159
163 QOF_HOW_RND_NEVER = 0x08
164 };
QOF_HOW_RND_CEIL
Definition: qofnumeric.h:135
QOF_HOW_RND_TRUNC
Definition: qofnumeric.h:138
QOF_HOW_RND_FLOOR
Definition: qofnumeric.h:132
QOF_HOW_RND_NEVER
Definition: qofnumeric.h:163
QOF_HOW_RND_PROMOTE
Definition: qofnumeric.h:141
QOF_HOW_RND_ROUND
Definition: qofnumeric.h:158
QOF_HOW_RND_ROUND_HALF_DOWN
Definition: qofnumeric.h:146
QOF_HOW_RND_ROUND_HALF_UP
Definition: qofnumeric.h:151

## ◆ anonymous enum

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.

168 {
174 QOF_HOW_DENOM_EXACT = 0x10,
175
181 QOF_HOW_DENOM_REDUCE = 0x20,
182
186 QOF_HOW_DENOM_LCD = 0x30,
187
192 QOF_HOW_DENOM_FIXED = 0x40,
193
197 QOF_HOW_DENOM_SIGFIG = 0x50
198 };
QOF_HOW_DENOM_SIGFIG
Definition: qofnumeric.h:197
QOF_HOW_DENOM_EXACT
Definition: qofnumeric.h:174
QOF_HOW_DENOM_REDUCE
Definition: qofnumeric.h:181
QOF_HOW_DENOM_FIXED
Definition: qofnumeric.h:192
QOF_HOW_DENOM_LCD
Definition: qofnumeric.h:186

## ◆ QofNumericErrorCode

enum QofNumericErrorCode

Error codes

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

Definition at line 207 of file qofnumeric.h.

208 {
209 QOF_ERROR_OK = 0,
210 QOF_ERROR_ARG = -1,
211 QOF_ERROR_OVERFLOW = -2,
214 QOF_ERROR_DENOM_DIFF = -3,
215
218 QOF_ERROR_REMAINDER = -4
219 } QofNumericErrorCode;
QOF_ERROR_ARG
Definition: qofnumeric.h:210
QOF_ERROR_OK
Definition: qofnumeric.h:209
QOF_ERROR_REMAINDER
Definition: qofnumeric.h:218
QofNumericErrorCode
QofNumericErrorCode
Definition: qofnumeric.h:207
QOF_ERROR_DENOM_DIFF
Definition: qofnumeric.h:214
QOF_ERROR_OVERFLOW
Definition: qofnumeric.h:211

## Function Documentation

## ◆ qof_numeric_abs()

QofNumeric qof_numeric_abs | ( | QofNumeric | a | ) |

Return the absolute value of the argument

Definition at line 650 of file qofnumeric.c.

651 {
652 if (qof_numeric_check (a))
653 return qof_numeric_error (QOF_ERROR_ARG);
654 return qof_numeric_create (ABS (a.num), a.denom);
655 }
qof_numeric_check
QofNumericErrorCode qof_numeric_check(QofNumeric in)
Definition: qofnumeric.c:44
QOF_ERROR_ARG
Definition: qofnumeric.h:210
qof_numeric_error
QofNumeric qof_numeric_error(QofNumericErrorCode error_code)
Definition: qofnumeric.c:1004
qof_numeric_create
static QofNumeric qof_numeric_create(gint64 num, gint64 denom)
Definition: qofnumeric.h:243

## ◆ qof_numeric_add()

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

Return a+b.

Definition at line 300 of file qofnumeric.c.

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

## ◆ qof_numeric_add_fixed()

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,
414 QOF_HOW_DENOM_FIXED | QOF_HOW_RND_NEVER);
415 }
QOF_HOW_RND_NEVER
Definition: qofnumeric.h:163
qof_numeric_add
QofNumeric qof_numeric_add(QofNumeric a, QofNumeric b, gint64 denom, gint how)
Definition: qofnumeric.c:300
QOF_HOW_DENOM_FIXED
Definition: qofnumeric.h:192
QOF_DENOM_AUTO
#define QOF_DENOM_AUTO
Definition: qofnumeric.h:231

## ◆ qof_numeric_add_with_error()

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

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

Definition at line 1014 of file qofnumeric.c.

1016 {
1017
1018 QofNumeric sum = qof_numeric_add (a, b, denom, how);
1019 QofNumeric exact = qof_numeric_add (a, b, QOF_DENOM_AUTO,
1020 QOF_HOW_DENOM_REDUCE);
1021 QofNumeric err = qof_numeric_sub (sum, exact, QOF_DENOM_AUTO,
1022 QOF_HOW_DENOM_REDUCE);
1023
1024 if (error)
1025 *error = err;
1026 return sum;
1027 }
_QofNumeric
Definition: qofnumeric.h:52
qof_numeric_sub
QofNumeric qof_numeric_sub(QofNumeric a, QofNumeric b, gint64 denom, gint how)
Definition: qofnumeric.c:388
qof_numeric_add
QofNumeric qof_numeric_add(QofNumeric a, QofNumeric b, gint64 denom, gint how)
Definition: qofnumeric.c:300
QOF_HOW_DENOM_REDUCE
Definition: qofnumeric.h:181
QOF_DENOM_AUTO
#define QOF_DENOM_AUTO
Definition: qofnumeric.h:231

## ◆ qof_numeric_check()

QofNumericErrorCode qof_numeric_check | ( | QofNumeric | a | ) |
| inline

Check for error signal in value. Returns QOF_ERROR_OK (==0) if the number appears to be valid, otherwise it returns the type of error. Error values always have a denominator of zero.

Definition at line 44 of file qofnumeric.c.

45 {
46 if (in.denom != 0)
47 return QOF_ERROR_OK;
48 else if (in.num)
49 {
50 if ((0 < in.num) || (-4 > in.num))
51 in.num = (gint64) QOF_ERROR_OVERFLOW;
52 return (QofNumericErrorCode) in.num;
53 }
54 else
55 return QOF_ERROR_ARG;
56 }
QOF_ERROR_ARG
Definition: qofnumeric.h:210
QOF_ERROR_OK
Definition: qofnumeric.h:209
QofNumericErrorCode
QofNumericErrorCode
Definition: qofnumeric.h:207
QOF_ERROR_OVERFLOW
Definition: qofnumeric.h:211

## ◆ qof_numeric_compare()

gint qof_numeric_compare | ( | QofNumeric | a,
|  | QofNumeric | b
| ) |  |

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

Definition at line 174 of file qofnumeric.c.

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

## ◆ qof_numeric_convert()

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

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

Definition at line 662 of file qofnumeric.c.

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

## ◆ qof_numeric_convert_with_error()

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.

## ◆ qof_numeric_create()

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 }
_QofNumeric
Definition: qofnumeric.h:52

## ◆ qof_numeric_dbg_to_string()

gchar* qof_numeric_dbg_to_string | ( | QofNumeric | n | ) |

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

Definition at line 1103 of file qofnumeric.c.

1104 {
1105 static gchar buff[1000];
1106 static gchar *p = buff;
1107 gint64 tmpnum = n.num;
1108 gint64 tmpdenom = n.denom;
1109
1110 p += 100;
1111 if (p - buff >= 1000)
1112 p = buff;
1113
1114 sprintf (p, "%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, tmpnum,
1115 tmpdenom);
1116
1117 return p;
1118 }

## ◆ qof_numeric_denom()

static gint64 qof_numeric_denom | ( | QofNumeric | a | ) |
| inlinestatic

Return denominator

Definition at line 291 of file qofnumeric.h.

292 {
293 return a.denom;
294 }

## ◆ qof_numeric_div()

QofNumeric qof_numeric_div | ( | QofNumeric | x,
|  | QofNumeric | y,
|  | gint64 | denom,
|  | gint | how
| ) |  |

Division. Note that division can overflow, in the following sense: if we write x=a/b and y=c/d then x/y = (a*d)/(b*c)

If, after eliminating all common factors between the numerator (a*d) and the denominator (b*c), then if either the numerator and/or the denominator are still greater than 2^63, then the division has overflowed.

Definition at line 516 of file qofnumeric.c.

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

## ◆ qof_numeric_div_with_error()

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

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

Definition at line 1071 of file qofnumeric.c.

1073 {
1074 QofNumeric quot = qof_numeric_div (a, b, denom, how);
1075 QofNumeric exact = qof_numeric_div (a, b, QOF_DENOM_AUTO,
1076 QOF_HOW_DENOM_REDUCE);
1077 QofNumeric err = qof_numeric_sub (quot, exact,
1078 QOF_DENOM_AUTO, QOF_HOW_DENOM_REDUCE);
1079 if (error)
1080 *error = err;
1081 return quot;
1082 }
_QofNumeric
Definition: qofnumeric.h:52
qof_numeric_sub
QofNumeric qof_numeric_sub(QofNumeric a, QofNumeric b, gint64 denom, gint how)
Definition: qofnumeric.c:388
QOF_HOW_DENOM_REDUCE
Definition: qofnumeric.h:181
qof_numeric_div
QofNumeric qof_numeric_div(QofNumeric a, QofNumeric b, gint64 denom, gint how)
Definition: qofnumeric.c:516
QOF_DENOM_AUTO
#define QOF_DENOM_AUTO
Definition: qofnumeric.h:231

## ◆ qof_numeric_eq()

gboolean qof_numeric_eq | ( | QofNumeric | a,
|  | QofNumeric | b
| ) |  |

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

Definition at line 223 of file qofnumeric.c.

224 {
225 return ((a.num == b.num) && (a.denom == b.denom));
226 }

## ◆ qof_numeric_equal()

gboolean qof_numeric_equal | ( | QofNumeric | a,
|  | QofNumeric | b
| ) |  |

Equivalence predicate: Returns TRUE (1) if a and b represent the same number. That is, return TRUE if the ratios, when reduced by eliminating common factors, are identical.

Definition at line 233 of file qofnumeric.c.

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

## ◆ qof_numeric_error()

QofNumeric qof_numeric_error | ( | QofNumericErrorCode | error_code | ) |

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

Definition at line 1004 of file qofnumeric.c.

1005 {
1006 return qof_numeric_create (error_code, 0LL);
1007 }
qof_numeric_create
static QofNumeric qof_numeric_create(gint64 num, gint64 denom)
Definition: qofnumeric.h:243

## ◆ qof_numeric_from_double()

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

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

Definition at line 919 of file qofnumeric.c.

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

## ◆ qof_numeric_from_string()

gboolean qof_numeric_from_string | ( | const gchar * | str,
|  | QofNumeric * | n
| ) |  |

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

Definition at line 1121 of file qofnumeric.c.

1122 {
1123 size_t num_read;
1124 gint64 tmpnum;
1125 gint64 tmpdenom;
1126
1127 if (!str)
1128 return FALSE;
1129
1130 #ifdef QOF_DEPRECATED
1131 /* must use "<" here because %n's effects aren't well defined */
1132 if (sscanf (str, " " QOF_SCANF_LLD "/" QOF_SCANF_LLD "%n",
1133 &tmpnum, &tmpdenom, &num_read) < 2)
1134 {
1135 return FALSE;
1136 }
1137 #else
1138 tmpnum = strtoll (str, NULL, 0);
1139 str = strchr (str, '/');
1140 if (!str)
1141 return FALSE;
1142 str++;
1143 tmpdenom = strtoll (str, NULL, 0);
1144 num_read = strspn (str, "0123456789");
1145 #endif
1146 n->num = tmpnum;
1147 n->denom = tmpdenom;
1148 return TRUE;
1149 }
QOF_SCANF_LLD
#define QOF_SCANF_LLD
Definition: qofutil.h:47

## ◆ qof_numeric_mul()

QofNumeric qof_numeric_mul | ( | QofNumeric | a,
|  | QofNumeric | b,
|  | gint64 | denom,
|  | gint | how
| ) |  |

Multiply a times b, returning the product. An overflow may occur if the result of the multiplication can't be represented as a ratio of 64-bit int's after removing common factors.

Definition at line 405 of file qofnumeric.c.

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

## ◆ qof_numeric_mul_with_error()

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

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

Definition at line 1052 of file qofnumeric.c.

1054 {
1055 QofNumeric prod = qof_numeric_mul (a, b, denom, how);
1056 QofNumeric exact = qof_numeric_mul (a, b, QOF_DENOM_AUTO,
1057 QOF_HOW_DENOM_REDUCE);
1058 QofNumeric err = qof_numeric_sub (prod, exact, QOF_DENOM_AUTO,
1059 QOF_HOW_DENOM_REDUCE);
1060 if (error)
1061 *error = err;
1062 return prod;
1063 }
qof_numeric_mul
QofNumeric qof_numeric_mul(QofNumeric a, QofNumeric b, gint64 denom, gint how)
Definition: qofnumeric.c:405
_QofNumeric
Definition: qofnumeric.h:52
qof_numeric_sub
QofNumeric qof_numeric_sub(QofNumeric a, QofNumeric b, gint64 denom, gint how)
Definition: qofnumeric.c:388
QOF_HOW_DENOM_REDUCE
Definition: qofnumeric.h:181
QOF_DENOM_AUTO
#define QOF_DENOM_AUTO
Definition: qofnumeric.h:231

## ◆ qof_numeric_neg()

QofNumeric qof_numeric_neg | ( | QofNumeric | a | ) |

Negate the argument

Definition at line 637 of file qofnumeric.c.

638 {
639 if (qof_numeric_check (a))
640 return qof_numeric_error (QOF_ERROR_ARG);
641 return qof_numeric_create (-a.num, a.denom);
642 }
qof_numeric_check
QofNumericErrorCode qof_numeric_check(QofNumeric in)
Definition: qofnumeric.c:44
QOF_ERROR_ARG
Definition: qofnumeric.h:210
qof_numeric_error
QofNumeric qof_numeric_error(QofNumericErrorCode error_code)
Definition: qofnumeric.c:1004
qof_numeric_create
static QofNumeric qof_numeric_create(gint64 num, gint64 denom)
Definition: qofnumeric.h:243

## ◆ qof_numeric_negative_p()

gboolean qof_numeric_negative_p | ( | QofNumeric | a | ) |

Returns 1 if a < 0, otherwise returns 0.

Definition at line 137 of file qofnumeric.c.

138 {
139 if (qof_numeric_check (a))
140 return 0;
141 else
142 {
143 if ((a.num < 0) && (a.denom != 0))
144 return 1;
145 else
146 return 0;
147 }
148 }
qof_numeric_check
QofNumericErrorCode qof_numeric_check(QofNumeric in)
Definition: qofnumeric.c:44

## ◆ qof_numeric_num()

static gint64 qof_numeric_num | ( | QofNumeric | a | ) |
| inlinestatic

Return numerator

Definition at line 284 of file qofnumeric.h.

285 {
286 return a.num;
287 }

## ◆ qof_numeric_positive_p()

gboolean qof_numeric_positive_p | ( | QofNumeric | a | ) |

Returns 1 if a > 0, otherwise returns 0.

Definition at line 155 of file qofnumeric.c.

156 {
157 if (qof_numeric_check (a))
158 return 0;
159 else
160 {
161 if ((a.num > 0) && (a.denom != 0))
162 return 1;
163 else
164 return 0;
165 }
166 }
qof_numeric_check
QofNumericErrorCode qof_numeric_check(QofNumeric in)
Definition: qofnumeric.c:44

## ◆ qof_numeric_reduce()

QofNumeric qof_numeric_reduce | ( | QofNumeric | in | ) |

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

Definition at line 888 of file qofnumeric.c.

889 {
890 gint64 t;
891 gint64 num = (in.num < 0) ? (-in.num) : in.num;
892 gint64 denom = in.denom;
893 QofNumeric out;
894
895 if (qof_numeric_check (in))
896 return qof_numeric_error (QOF_ERROR_ARG);
897
898 /* The strategy is to use Euclid's algorithm */
899 while (denom > 0)
900 {
901 t = num % denom;
902 num = denom;
903 denom = t;
904 }
905 /* num now holds the GCD (Greatest Common Divisor) */
906
907 /* All calculations are done on positive num, since it's not
908 * well defined what % does for negative values */
909 out.num = in.num / num;
910 out.denom = in.denom / num;
911 return out;
912 }
qof_numeric_check
QofNumericErrorCode qof_numeric_check(QofNumeric in)
Definition: qofnumeric.c:44
QOF_ERROR_ARG
Definition: qofnumeric.h:210
qof_numeric_error
QofNumeric qof_numeric_error(QofNumericErrorCode error_code)
Definition: qofnumeric.c:1004
_QofNumeric
Definition: qofnumeric.h:52

## ◆ qof_numeric_same()

gint qof_numeric_same | ( | QofNumeric | a,
|  | QofNumeric | b,
|  | gint64 | denom,
|  | gint | how
| ) |  |

Equivalence predicate: Convert both a and b to denom using the specified DENOM and method HOW, and compare numerators the results using QofNumeric_equal.

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

Definition at line 285 of file qofnumeric.c.

286 {
287 QofNumeric aconv, bconv;
288
289 aconv = qof_numeric_convert (a, denom, how);
290 bconv = qof_numeric_convert (b, denom, how);
291
292 return (qof_numeric_equal (aconv, bconv));
293 }
qof_numeric_equal
gboolean qof_numeric_equal(QofNumeric a, QofNumeric b)
Definition: qofnumeric.c:233
_QofNumeric
Definition: qofnumeric.h:52
qof_numeric_convert
QofNumeric qof_numeric_convert(QofNumeric in, gint64 denom, gint how)
Definition: qofnumeric.c:662

## ◆ qof_numeric_sub()

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

Return a-b.

Definition at line 388 of file qofnumeric.c.

389 {
390 QofNumeric nb;
391
392 if (qof_numeric_check (a) || qof_numeric_check (b))
393 return qof_numeric_error (QOF_ERROR_ARG);
394
395 nb = b;
396 nb.num = -nb.num;
397 return qof_numeric_add (a, nb, denom, how);
398 }
qof_numeric_check
QofNumericErrorCode qof_numeric_check(QofNumeric in)
Definition: qofnumeric.c:44
QOF_ERROR_ARG
Definition: qofnumeric.h:210
qof_numeric_error
QofNumeric qof_numeric_error(QofNumericErrorCode error_code)
Definition: qofnumeric.c:1004
_QofNumeric
Definition: qofnumeric.h:52
qof_numeric_add
QofNumeric qof_numeric_add(QofNumeric a, QofNumeric b, gint64 denom, gint how)
Definition: qofnumeric.c:300

## ◆ qof_numeric_sub_fixed()

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,
425 QOF_HOW_DENOM_FIXED | QOF_HOW_RND_NEVER);
426 }
QOF_HOW_RND_NEVER
Definition: qofnumeric.h:163
qof_numeric_sub
QofNumeric qof_numeric_sub(QofNumeric a, QofNumeric b, gint64 denom, gint how)
Definition: qofnumeric.c:388
QOF_HOW_DENOM_FIXED
Definition: qofnumeric.h:192
QOF_DENOM_AUTO
#define QOF_DENOM_AUTO
Definition: qofnumeric.h:231

## ◆ qof_numeric_sub_with_error()

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

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

Definition at line 1034 of file qofnumeric.c.

1036 {
1037 QofNumeric diff = qof_numeric_sub (a, b, denom, how);
1038 QofNumeric exact = qof_numeric_sub (a, b, QOF_DENOM_AUTO,
1039 QOF_HOW_DENOM_REDUCE);
1040 QofNumeric err = qof_numeric_sub (diff, exact, QOF_DENOM_AUTO,
1041 QOF_HOW_DENOM_REDUCE);
1042 if (error)
1043 *error = err;
1044 return diff;
1045 }
_QofNumeric
Definition: qofnumeric.h:52
qof_numeric_sub
QofNumeric qof_numeric_sub(QofNumeric a, QofNumeric b, gint64 denom, gint how)
Definition: qofnumeric.c:388
QOF_HOW_DENOM_REDUCE
Definition: qofnumeric.h:181
QOF_DENOM_AUTO
#define QOF_DENOM_AUTO
Definition: qofnumeric.h:231

## ◆ qof_numeric_to_double()

gdouble qof_numeric_to_double | ( | QofNumeric | in | ) |

Convert numeric to floating-point value.

Definition at line 991 of file qofnumeric.c.

992 {
993 if (in.denom > 0)
994 return (gdouble) in.num / (gdouble) in.denom;
995 else
996 return (gdouble) (in.num * -in.denom);
997 }

## ◆ qof_numeric_to_string()

gchar* qof_numeric_to_string | ( | QofNumeric | n | ) |

Convert to string. The returned buffer is to be g_free'd by the caller (it was allocated through g_strdup)

Definition at line 1089 of file qofnumeric.c.

1090 {
1091 gchar *result;
1092 gint64 tmpnum = n.num;
1093 gint64 tmpdenom = n.denom;
1094
1095 result =
1096 g_strdup_printf ("%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, tmpnum,
1097 tmpdenom);
1098
1099 return result;
1100 }

## ◆ qof_numeric_zero()

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 }
qof_numeric_create
static QofNumeric qof_numeric_create(gint64 num, gint64 denom)
Definition: qofnumeric.h:243

## ◆ qof_numeric_zero_p()

gboolean qof_numeric_zero_p | ( | QofNumeric | a | ) |

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

Definition at line 119 of file qofnumeric.c.

120 {
121 if (qof_numeric_check (a))
122 return 0;
123 else
124 {
125 if ((a.num == 0) && (a.denom != 0))
126 return 1;
127 else
128 return 0;
129 }
130 }
qof_numeric_check
QofNumericErrorCode qof_numeric_check(QofNumeric in)
Definition: qofnumeric.c:44