1 /********************************************************************
2  * qofnumeric.h - A rational number library                         *
3  * This program is free software; you can redistribute it and/or    *
4  * modify it under the terms of the GNU General Public License as   *
5  * published by the Free Software Foundation; either version 2 of   *
6  * the License, or (at your option) any later version.              *
7  *                                                                  *
8  * This program is distributed in the hope that it will be useful,  *
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
11  * GNU General Public License for more details.                     *
12  *                                                                  *
13  * You should have received a copy of the GNU General Public License*
14  * along with this program; if not, contact:                        *
15  *                                                                  *
16  * Free Software Foundation           Voice:  +1-617-542-5942       *
17  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
18  * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
19  *                                                                  *
20  *******************************************************************/
21 
22 /** @addtogroup Numeric
23 
24     The 'Numeric' functions provide a way of working with rational
25     numbers while maintaining strict control over rounding errors
26     when adding rationals with different denominators.  The Numeric
27     class is primarily used for working with monetary amounts,
28     where the denominator typically represents the smallest fraction
29     of the currency (e.g. pennies, centimes).  The numeric class
30     can handle any fraction (e.g. twelfth's) and is not limited
31     to fractions that are powers of ten.
32 
33     A 'Numeric' value represents a number in rational form, with a
34     64-bit integer as numerator and denominator.  Rationals are
35     ideal for many uses, such as performing exact, roundoff-error-free
36     addition and multiplication, but 64-bit rationals do not have
37     the dynamic range of floating point numbers.
38 
39 See \ref qofnumericexample
40 
41 @{ */
42 /** @file qofnumeric.h
43     @brief An exact-rational-number library for QOF.
44     @author Copyright (C) 2000 Bill Gribble
45     @author Copyright (C) 2004 Linas Vepstas <linas@linas.org>
46     @author Copyright (c) 2006 Neil Williams <linux@codehelp.co.uk>
47 */
48 
49 #ifndef QOF_NUMERIC_H
50 #define QOF_NUMERIC_H
51 
52 struct _QofNumeric
53 {
54 	gint64 num;
55 	gint64 denom;
56 };
57 
58 /** @brief A rational-number type
59  *
60  * This is a rational number, defined by numerator and denominator. */
61 typedef struct _QofNumeric QofNumeric;
62 
63 /** @name Standard Arguments to most functions
64 
65     Most of the QofNumeric arithmetic functions take two arguments
66     in addition to their numeric args: 'denom', which is the denominator
67     to use in the output QofNumeric object, and 'how'. which
68     describes how the arithmetic result is to be converted to that
69     denominator. This combination of output denominator and rounding policy
70     allows the results of financial and other rational computations to be
71     properly rounded to the appropriate units.
72 
73     Valid values for denom are:
74     QOF_DENOM_AUTO  -- compute denominator exactly
75     integer n       -- Force the denominator of the result to be this integer
76     QOF_DENOM_RECIPROCAL -- Use 1/n as the denominator (???huh???)
77 
78     Valid values for 'how' are bitwise combinations of zero or one
79     "rounding instructions" with zero or one "denominator types".
80     Valid rounding instructions are:
81         QOF_HOW_RND_FLOOR
82         QOF_HOW_RND_CEIL
83         QOF_HOW_RND_TRUNC
84         QOF_HOW_RND_PROMOTE
85         QOF_HOW_RND_ROUND_HALF_DOWN
86         QOF_HOW_RND_ROUND_HALF_UP
87         QOF_HOW_RND_ROUND
88         QOF_HOW_RND_NEVER
89 
90     The denominator type specifies how to compute a denominator if
91     QOF_DENOM_AUTO is specified as the 'denom'. Valid
92     denominator types are:
93         QOF_HOW_DENOM_EXACT
94         QOF_HOW_DENOM_REDUCE
95         QOF_HOW_DENOM_LCD
96         QOF_HOW_DENOM_FIXED
97         QOF_HOW_DENOM_SIGFIGS(N)
98 
99    To use traditional rational-number operational semantics (all results
100    are exact and are reduced to relatively-prime fractions) pass the
101    argument QOF_DENOM_AUTO as 'denom' and
102    QOF_HOW_DENOM_REDUCE| QOF_HOW_RND_NEVER as 'how'.
103 
104    To enforce strict financial semantics (such that all operands must have
105    the same denominator as each other and as the result), use
106    QOF_DENOM_AUTO as 'denom' and
107    QOF_HOW_DENOM_FIXED | QOF_HOW_RND_NEVER as 'how'.
108 @{
109 */
110 
111 /** \brief bitmasks for HOW flags.
112 
113  * bits 8-15 of 'how' are reserved for the number of significant
114  * digits to use in the output with QOF_HOW_DENOM_SIGFIG
115  */
116 #define QOF_NUMERIC_RND_MASK     0x0000000f
117 #define QOF_NUMERIC_DENOM_MASK   0x000000f0
118 #define QOF_NUMERIC_SIGFIGS_MASK 0x0000ff00
119 
120 /** \brief Rounding/Truncation modes for operations.
121 
122  *  Rounding instructions control how fractional parts in the specified
123  *  denominator affect the result. For example, if a computed result is
124  *  "3/4" but the specified denominator for the return value is 2, should
125  *  the return value be "1/2" or "2/2"?
126  *
127  * Possible rounding instructions are:
128  */
129 enum
130 {
131   /** Round toward -infinity */
132 	QOF_HOW_RND_FLOOR = 0x01,
133 
134   /** Round toward +infinity */
135 	QOF_HOW_RND_CEIL = 0x02,
136 
137   /** Truncate fractions (round toward zero) */
138 	QOF_HOW_RND_TRUNC = 0x03,
139 
140   /** Promote fractions (round away from zero) */
141 	QOF_HOW_RND_PROMOTE = 0x04,
142 
143   /** Round to the nearest integer, rounding toward zero
144    *  when there are two equidistant nearest integers.
145    */
146 	QOF_HOW_RND_ROUND_HALF_DOWN = 0x05,
147 
148   /** Round to the nearest integer, rounding away from zero
149    *  when there are two equidistant nearest integers.
150    */
151 	QOF_HOW_RND_ROUND_HALF_UP = 0x06,
152 
153   /** Use unbiased ("banker's") rounding. This rounds to the
154    *  nearest integer, and to the nearest even integer when there
155    *  are two equidistant nearest integers. This is generally the
156    *  one you should use for financial quantities.
157    */
158 	QOF_HOW_RND_ROUND = 0x07,
159 
160   /** Never round at all, and signal an error if there is a
161    *  fractional result in a computation.
162    */
163 	QOF_HOW_RND_NEVER = 0x08
164 };
165 
166 /** How to compute a denominator, or'ed into the "how" field. */
167 enum
168 {
169   /** Use any denominator which gives an exactly correct ratio of
170    *  numerator to denominator. Use EXACT when you do not wish to
171    *  lose any information in the result but also do not want to
172    *  spend any time finding the "best" denominator.
173    */
174 	QOF_HOW_DENOM_EXACT = 0x10,
175 
176   /** Reduce the result value by common factor elimination,
177    *  using the smallest possible value for the denominator that
178    *  keeps the correct ratio. The numerator and denominator of
179    *  the result are relatively prime.
180    */
181 	QOF_HOW_DENOM_REDUCE = 0x20,
182 
183   /** Find the least common multiple of the arguments' denominators
184    *  and use that as the denominator of the result.
185    */
186 	QOF_HOW_DENOM_LCD = 0x30,
187 
188   /** All arguments are required to have the same denominator,
189    *  that denominator is to be used in the output, and an error
190    *  is to be signaled if any argument has a different denominator.
191    */
192 	QOF_HOW_DENOM_FIXED = 0x40,
193 
194   /** Round to the number of significant figures given in the rounding
195    *  instructions by the QOF_HOW_DENOM_SIGFIGS () macro.
196    */
197 	QOF_HOW_DENOM_SIGFIG = 0x50
198 };
199 
200 /** Build a 'how' value that will generate a denominator that will
201  *  keep at least n significant figures in the result.
202  */
203 #define QOF_HOW_DENOM_SIGFIGS( n ) ( ((( n ) & 0xff) << 8) | QOF_HOW_DENOM_SIGFIG)
204 #define QOF_HOW_GET_SIGFIGS( a ) ( (( a ) & 0xff00 ) >> 8)
205 
206 /** Error codes */
207 typedef enum
208 {
209 	QOF_ERROR_OK = 0,	   /**< No error */
210 	QOF_ERROR_ARG = -1,	   /**< Argument is not a valid number */
211 	QOF_ERROR_OVERFLOW = -2,   /**< Intermediate result overflow */
212 
213   /** QOF_HOW_DENOM_FIXED was specified, but argument denominators differed.  */
214 	QOF_ERROR_DENOM_DIFF = -3,
215 
216   /** QOF_HOW_RND_NEVER  was specified, but the result could not be
217    *  converted to the desired denominator without a remainder. */
218 	QOF_ERROR_REMAINDER = -4
219 } QofNumericErrorCode;
220 
221 
222 /** Values that can be passed as the 'denom' argument.
223  *  The include a positive number n to be used as the
224  *  denominator of the output value.  Other possibilities
225  *  include the list below:
226  */
227 
228 /** Compute an appropriate denominator automatically. Flags in
229  *  the 'how' argument will specify how to compute the denominator.
230  */
231 #define QOF_DENOM_AUTO 0
232 
233 /** Use the value 1/n as the denominator of the output value. */
234 #define QOF_DENOM_RECIPROCAL( a ) (- ( a ))
235 
236 /**  @} */
237 
238 /** @name Constructors
239 @{
240 */
241 /** Make a QofNumeric from numerator and denominator */
242 static inline QofNumeric
qof_numeric_create(gint64 num,gint64 denom)243 qof_numeric_create (gint64 num, gint64 denom)
244 {
245 	QofNumeric out;
246 	out.num = num;
247 	out.denom = denom;
248 	return out;
249 }
250 
251 /** create a zero-value QofNumeric */
252 static inline QofNumeric
qof_numeric_zero(void)253 qof_numeric_zero (void)
254 {
255 	return qof_numeric_create (0, 1);
256 }
257 
258 /** Convert a floating-point number to a QofNumeric.
259  *  Both 'denom' and 'how' are used as in arithmetic,
260  *  but QOF_DENOM_AUTO is not recognized; a denominator
261  *  must be specified either explicitctly or through sigfigs.
262  */
263 QofNumeric
264 qof_numeric_from_double (gdouble in, gint64 denom, gint how);
265 
266 /** Read a QofNumeric from str, skipping any leading whitespace.
267  *  Return TRUE on success and store the resulting value in "n".
268  *  Return NULL on error. */
269 gboolean
270 qof_numeric_from_string (const gchar * str, QofNumeric * n);
271 
272 /** Create a QofNumeric object that signals the error condition
273  *  noted by error_code, rather than a number.
274  */
275 QofNumeric
276 qof_numeric_error (QofNumericErrorCode error_code);
277 /** @} */
278 
279 /** @name Value Accessors
280  @{
281 */
282 /** Return numerator */
283 static inline gint64
qof_numeric_num(QofNumeric a)284 qof_numeric_num (QofNumeric a)
285 {
286 	return a.num;
287 }
288 
289 /** Return denominator */
290 static inline gint64
qof_numeric_denom(QofNumeric a)291 qof_numeric_denom (QofNumeric a)
292 {
293 	return a.denom;
294 }
295 
296 /** Convert numeric to floating-point value. */
297 gdouble
298 qof_numeric_to_double (QofNumeric in);
299 
300 /** Convert to string. The returned buffer is to be g_free'd by the
301  *  caller (it was allocated through g_strdup) */
302 gchar *
303 qof_numeric_to_string (QofNumeric n);
304 
305 /** Convert to string. Uses a static, non-thread-safe buffer.
306  *  For internal use only. */
307 gchar *
308 qof_numeric_dbg_to_string (QofNumeric n);
309 /** @}*/
310 
311 /** @name Comparisons and Predicates
312  @{
313 */
314 /** Check for error signal in value. Returns QOF_ERROR_OK (==0) if
315  *  the number appears to be valid, otherwise it returns the
316  *  type of error.  Error values always have a denominator of zero.
317  */
318 QofNumericErrorCode
319 qof_numeric_check (QofNumeric a);
320 
321 /** Returns 1 if a>b, -1 if b>a, 0 if a == b  */
322 gint
323 qof_numeric_compare (QofNumeric a, QofNumeric b);
324 
325 /** Returns 1 if the given QofNumeric is 0 (zero), else returns 0. */
326 gboolean
327 qof_numeric_zero_p (QofNumeric a);
328 
329 /** Returns 1 if a < 0, otherwise returns 0. */
330 gboolean
331 qof_numeric_negative_p (QofNumeric a);
332 
333 /** Returns 1 if a > 0, otherwise returns 0. */
334 gboolean
335 qof_numeric_positive_p (QofNumeric a);
336 
337 /** Equivalence predicate: Returns TRUE (1) if a and b are
338  *  exactly the same (have the same numerator and denominator)
339  */
340 gboolean
341 qof_numeric_eq (QofNumeric a, QofNumeric b);
342 
343 /** Equivalence predicate: Returns TRUE (1) if a and b represent
344  *  the same number.  That is, return TRUE if the ratios, when
345  *  reduced by eliminating common factors, are identical.
346  */
347 gboolean
348 qof_numeric_equal (QofNumeric a, QofNumeric b);
349 
350 /** Equivalence predicate:
351  *  Convert both a and b to denom using the
352  *  specified DENOM and method HOW, and compare numerators
353  *  the results using QofNumeric_equal.
354  *
355   For example, if a == 7/16 and b == 3/4,
356   QofNumeric_same(a, b, 2, QOF_HOW_RND_TRUNC) == 1
357   because both 7/16 and 3/4 round to 1/2 under truncation. However,
358   QofNumeric_same(a, b, 2, QOF_HOW_RND_ROUND) == 0
359   because 7/16 rounds to 1/2 under unbiased rounding but 3/4 rounds
360   to 2/2.
361  */
362 gint
363 qof_numeric_same (QofNumeric a, QofNumeric b, gint64 denom, gint how);
364 /** @} */
365 
366 /** @name Arithmetic Operations
367  @{
368 */
369 /** Return a+b. */
370 QofNumeric
371 qof_numeric_add (QofNumeric a, QofNumeric b,
372 							 gint64 denom, gint how);
373 
374 /** Return a-b. */
375 QofNumeric
376 qof_numeric_sub (QofNumeric a, QofNumeric b,
377 							 gint64 denom, gint how);
378 
379 /** Multiply a times b, returning the product.  An overflow
380  *  may occur if the result of the multiplication can't
381  *  be represented as a ratio of 64-bit int's after removing
382  *  common factors.
383  */
384 QofNumeric
385 qof_numeric_mul (QofNumeric a, QofNumeric b,
386 							 gint64 denom, gint how);
387 
388 /** Division.  Note that division can overflow, in the following
389  *  sense: if we write x=a/b and y=c/d  then x/y = (a*d)/(b*c)
390  *  If, after eliminating all common factors between the numerator
391  *  (a*d) and the denominator (b*c),  then if either the numerator
392  *  and/or the denominator are *still* greater than 2^63, then
393  *  the division has overflowed.
394  */
395 QofNumeric
396 qof_numeric_div (QofNumeric x, QofNumeric y,
397 							 gint64 denom, gint how);
398 /** Negate the argument  */
399 QofNumeric
400 qof_numeric_neg (QofNumeric a);
401 
402 /** Return the absolute value of the argument */
403 QofNumeric
404 qof_numeric_abs (QofNumeric a);
405 
406 /**
407  * Shortcut for common case: QofNumeric_add(a, b, QOF_DENOM_AUTO,
408  *                        QOF_HOW_DENOM_FIXED | QOF_HOW_RND_NEVER);
409  */
410 static inline QofNumeric
qof_numeric_add_fixed(QofNumeric a,QofNumeric b)411 qof_numeric_add_fixed (QofNumeric a, QofNumeric b)
412 {
413 	return qof_numeric_add (a, b, QOF_DENOM_AUTO,
414 				QOF_HOW_DENOM_FIXED | QOF_HOW_RND_NEVER);
415 }
416 
417 /**
418  * Shortcut for most common case: QofNumeric_sub(a, b, QOF_DENOM_AUTO,
419  *                        QOF_HOW_DENOM_FIXED | QOF_HOW_RND_NEVER);
420  */
421 static inline QofNumeric
qof_numeric_sub_fixed(QofNumeric a,QofNumeric b)422 qof_numeric_sub_fixed (QofNumeric a, QofNumeric b)
423 {
424 	return qof_numeric_sub (a, b, QOF_DENOM_AUTO,
425 				QOF_HOW_DENOM_FIXED | QOF_HOW_RND_NEVER);
426 }
427 
428 /** @} */
429 
430 /** @name Arithmetic Functions with Exact Error Returns
431  @{
432 */
433 /** The same as QofNumeric_add, but uses 'error' for accumulating
434  *  conversion roundoff error. */
435 QofNumeric
436 qof_numeric_add_with_error (QofNumeric a, QofNumeric b,
437 										gint64 denom, gint how,
438 					QofNumeric * error);
439 
440 /** The same as QofNumeric_sub, but uses error for accumulating
441  *  conversion roundoff error. */
442 QofNumeric
443 qof_numeric_sub_with_error (QofNumeric a, QofNumeric b,
444 										gint64 denom, gint how,
445 					QofNumeric * error);
446 
447 /** The same as QofNumeric_mul, but uses error for
448  *  accumulating conversion roundoff error.
449  */
450 QofNumeric
451 qof_numeric_mul_with_error (QofNumeric a, QofNumeric b,
452 										gint64 denom, gint how,
453 					QofNumeric * error);
454 
455 /** The same as QofNumeric_div, but uses error for
456  *  accumulating conversion roundoff error.
457  */
458 QofNumeric
459 qof_numeric_div_with_error (QofNumeric a, QofNumeric b,
460 										gint64 denom, gint how,
461 					QofNumeric * error);
462 /** @} */
463 
464 /** @name Change Denominator
465  @{
466 */
467 /** Change the denominator of a QofNumeric value to the
468  *  specified denominator under standard arguments
469  *  'denom' and 'how'.
470  */
471 QofNumeric
472 qof_numeric_convert (QofNumeric in, gint64 denom, gint how);
473 
474 /** Same as QofNumeric_convert, but return a remainder
475  *  value for accumulating conversion error.
476 */
477 QofNumeric
478 qof_numeric_convert_with_error (QofNumeric in, gint64 denom,
479 								gint how, QofNumeric * error);
480 
481 /** Return input after reducing it by Greated Common Factor (GCF)
482  *  elimination */
483 QofNumeric qof_numeric_reduce (QofNumeric in);
484 /** @} */
485 
486 /** @name Deprecated, backwards-compatible definitions
487   @{
488 */
489 #define QOF_RND_FLOOR			QOF_HOW_RND_FLOOR
490 #define QOF_RND_CEIL 			QOF_HOW_RND_CEIL
491 #define QOF_RND_TRUNC			QOF_HOW_RND_TRUNC
492 #define QOF_RND_PROMOTE 		QOF_HOW_RND_PROMOTE
493 #define QOF_RND_ROUND_HALF_DOWN	QOF_HOW_RND_ROUND_HALF_DOWN
494 #define QOF_RND_ROUND_HALF_UP 	QOF_HOW_RND_ROUND_HALF_UP
495 #define QOF_RND_ROUND			QOF_HOW_RND_ROUND
496 #define QOF_RND_NEVER			QOF_HOW_RND_NEVER
497 
498 #define QOF_DENOM_EXACT  		QOF_HOW_DENOM_EXACT
499 #define QOF_DENOM_REDUCE 		QOF_HOW_DENOM_REDUCE
500 #define QOF_DENOM_LCD   		QOF_HOW_DENOM_LCD
501 #define QOF_DENOM_FIXED 		QOF_HOW_DENOM_FIXED
502 #define QOF_DENOM_SIGFIG 		QOF_HOW_DENOM_SIGFIG
503 
504 #define QOF_DENOM_SIGFIGS(X)  	QOF_HOW_DENOM_SIGFIGS(X)
505 #define QOF_NUMERIC_GET_SIGFIGS(X) QOF_HOW_GET_SIGFIGS(X)
506 /** @} */
507 /** @} */
508 #endif
509