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.
EXAMPLE
-------
The following program finds the best gnc_numeric approximation to the math.h constant M_PI given a maximum denominator. For large denominators, the gnc_numeric approximation is accurate to more decimal places than will generally be needed, but in some cases this may not be good enough. For example,
M_PI = 3.14159265358979323846
245850922 / 78256779 = 3.14159265358979311599 (16 sig figs)
3126535 / 995207 = 3.14159265358865047446 (12 sig figs)
355 / 113 = 3.14159292035398252096 (7 sig figs)
#include <glib.h>
#include <qof.h>
#include <math.h>
int
main(int argc, char ** argv)
{
gnc_numeric approx, best;
double err, best_err=1.0;
double m_pi = M_PI;
gint64 denom;
gint64 max;
sscanf(argv[1], "%Ld", &max);
for (denom = 1; denom < max; denom++)
{
approx = double_to_gnc_numeric (m_pi, denom, GNC_RND_ROUND);
err = m_pi - gnc_numeric_to_double (approx);
if (fabs (err) < fabs (best_err))
{
best = approx;
best_err = err;
printf ("%Ld / %Ld = %.30f\n", gnc_numeric_num (best),
gnc_numeric_denom (best), gnc_numeric_to_double (best));
}
}
}
Files | |
| file | gnc-numeric.h |
| An exact-rational-number library for gnucash. (to be renamed qofnumeric.h in libqof2). | |
Data Structures | |
| struct | _gnc_numeric |
Arguments Standard Arguments to most functions | |
| Most of the gnc_numeric arithmetic functions take two arguments in addition to their numeric args: 'denom', which is the denominator to use in the output gnc_numeric 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: GNC_DENOM_AUTO -- compute denominator exactly integer n -- Force the denominator of the result to be this integer GNC_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: GNC_HOW_RND_FLOOR GNC_HOW_RND_CEIL GNC_HOW_RND_TRUNC GNC_HOW_RND_PROMOTE GNC_HOW_RND_ROUND_HALF_DOWN GNC_HOW_RND_ROUND_HALF_UP GNC_HOW_RND_ROUND GNC_HOW_RND_NEVER The denominator type specifies how to compute a denominator if GNC_DENOM_AUTO is specified as the 'denom'. Valid denominator types are: GNC_HOW_DENOM_EXACT GNC_HOW_DENOM_REDUCE GNC_HOW_DENOM_LCD GNC_HOW_DENOM_FIXED GNC_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 GNC_DENOM_AUTO as 'denom' and GNC_HOW_DENOM_REDUCE| GNC_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 GNC_DENOM_AUTO as 'denom' and GNC_HOW_DENOM_FIXED | GNC_HOW_RND_NEVER as 'how'. | |
| #define | GNC_NUMERIC_RND_MASK 0x0000000f |
| bitmasks for HOW flags. | |
| #define | GNC_NUMERIC_DENOM_MASK 0x000000f0 |
| #define | GNC_NUMERIC_SIGFIGS_MASK 0x0000ff00 |
| #define | GNC_HOW_DENOM_SIGFIGS(n) ( ((( n ) & 0xff) << 8) | GNC_HOW_DENOM_SIGFIG) |
| #define | GNC_HOW_GET_SIGFIGS(a) ( (( a ) & 0xff00 ) >> 8) |
| #define | GNC_DENOM_AUTO 0 |
| #define | GNC_DENOM_RECIPROCAL(a) (- ( a )) |
| enum | { GNC_HOW_RND_FLOOR = 0x01, GNC_HOW_RND_CEIL = 0x02, GNC_HOW_RND_TRUNC = 0x03, GNC_HOW_RND_PROMOTE = 0x04, GNC_HOW_RND_ROUND_HALF_DOWN = 0x05, GNC_HOW_RND_ROUND_HALF_UP = 0x06, GNC_HOW_RND_ROUND = 0x07, GNC_HOW_RND_NEVER = 0x08 } |
| Rounding/Truncation modes for operations. More... | |
| enum | { GNC_HOW_DENOM_EXACT = 0x10, GNC_HOW_DENOM_REDUCE = 0x20, GNC_HOW_DENOM_LCD = 0x30, GNC_HOW_DENOM_FIXED = 0x40, GNC_HOW_DENOM_SIGFIG = 0x50 } |
| enum | GNCNumericErrorCode { GNC_ERROR_OK = 0, GNC_ERROR_ARG = -1, GNC_ERROR_OVERFLOW = -2, GNC_ERROR_DENOM_DIFF = -3, GNC_ERROR_REMAINDER = -4 } |
Deprecated, backwards-compatible definitions | |
| #define | GNC_RND_FLOOR GNC_HOW_RND_FLOOR |
| #define | GNC_RND_CEIL GNC_HOW_RND_CEIL |
| #define | GNC_RND_TRUNC GNC_HOW_RND_TRUNC |
| #define | GNC_RND_PROMOTE GNC_HOW_RND_PROMOTE |
| #define | GNC_RND_ROUND_HALF_DOWN GNC_HOW_RND_ROUND_HALF_DOWN |
| #define | GNC_RND_ROUND_HALF_UP GNC_HOW_RND_ROUND_HALF_UP |
| #define | GNC_RND_ROUND GNC_HOW_RND_ROUND |
| #define | GNC_RND_NEVER GNC_HOW_RND_NEVER |
| #define | GNC_DENOM_EXACT GNC_HOW_DENOM_EXACT |
| #define | GNC_DENOM_REDUCE GNC_HOW_DENOM_REDUCE |
| #define | GNC_DENOM_LCD GNC_HOW_DENOM_LCD |
| #define | GNC_DENOM_FIXED GNC_HOW_DENOM_FIXED |
| #define | GNC_DENOM_SIGFIG GNC_HOW_DENOM_SIGFIG |
| #define | GNC_DENOM_SIGFIGS(X) GNC_HOW_DENOM_SIGFIGS(X) |
| #define | GNC_NUMERIC_GET_SIGFIGS(X) GNC_HOW_GET_SIGFIGS(X) |
Constructors | |
| static gnc_numeric | gnc_numeric_create (gint64 num, gint64 denom) |
| static gnc_numeric | gnc_numeric_zero (void) |
| gnc_numeric | double_to_gnc_numeric (double in, gint64 denom, gint how) |
| gboolean | string_to_gnc_numeric (const gchar *str, gnc_numeric *n) |
| gnc_numeric | gnc_numeric_error (GNCNumericErrorCode error_code) |
Value Accessors | |
| static gint64 | gnc_numeric_num (gnc_numeric a) |
| static gint64 | gnc_numeric_denom (gnc_numeric a) |
| double | gnc_numeric_to_double (gnc_numeric in) |
| gchar * | gnc_numeric_to_string (gnc_numeric n) |
| gchar * | gnc_num_dbg_to_string (gnc_numeric n) |
Comparisons and Predicates | |
| GNCNumericErrorCode | gnc_numeric_check (gnc_numeric a) |
| int | gnc_numeric_compare (gnc_numeric a, gnc_numeric b) |
| gboolean | gnc_numeric_zero_p (gnc_numeric a) |
| gboolean | gnc_numeric_negative_p (gnc_numeric a) |
| gboolean | gnc_numeric_positive_p (gnc_numeric a) |
| gboolean | gnc_numeric_eq (gnc_numeric a, gnc_numeric b) |
| gboolean | gnc_numeric_equal (gnc_numeric a, gnc_numeric b) |
| int | gnc_numeric_same (gnc_numeric a, gnc_numeric b, gint64 denom, gint how) |
Arithmetic Operations | |
| gnc_numeric | gnc_numeric_add (gnc_numeric a, gnc_numeric b, gint64 denom, gint how) |
| gnc_numeric | gnc_numeric_sub (gnc_numeric a, gnc_numeric b, gint64 denom, gint how) |
| gnc_numeric | gnc_numeric_mul (gnc_numeric a, gnc_numeric b, gint64 denom, gint how) |
| gnc_numeric | gnc_numeric_div (gnc_numeric x, gnc_numeric y, gint64 denom, gint how) |
| gnc_numeric | gnc_numeric_neg (gnc_numeric a) |
| gnc_numeric | gnc_numeric_abs (gnc_numeric a) |
| static gnc_numeric | gnc_numeric_add_fixed (gnc_numeric a, gnc_numeric b) |
| static gnc_numeric | gnc_numeric_sub_fixed (gnc_numeric a, gnc_numeric b) |
Arithmetic Functions with Exact Error Returns | |
| gnc_numeric | gnc_numeric_add_with_error (gnc_numeric a, gnc_numeric b, gint64 denom, gint how, gnc_numeric *error) |
| gnc_numeric | gnc_numeric_sub_with_error (gnc_numeric a, gnc_numeric b, gint64 denom, gint how, gnc_numeric *error) |
| gnc_numeric | gnc_numeric_mul_with_error (gnc_numeric a, gnc_numeric b, gint64 denom, gint how, gnc_numeric *error) |
| gnc_numeric | gnc_numeric_div_with_error (gnc_numeric a, gnc_numeric b, gint64 denom, gint how, gnc_numeric *error) |
Change Denominator | |
| gnc_numeric | gnc_numeric_convert (gnc_numeric in, gint64 denom, gint how) |
| gnc_numeric | gnc_numeric_convert_with_error (gnc_numeric in, gint64 denom, gint how, gnc_numeric *error) |
| gnc_numeric | gnc_numeric_reduce (gnc_numeric in) |
Typedefs | |
| typedef _gnc_numeric | gnc_numeric |
| An rational-number type. | |
|
|
Compute an appropriate denominator automatically. Flags in the 'how' argument will specify how to compute the denominator. Definition at line 275 of file gnc-numeric.h. |
|
|
Use the value 1/n as the denominator of the output value. Definition at line 278 of file gnc-numeric.h. |
|
|
Build a 'how' value that will generate a denominator that will keep at least n significant figures in the result. Definition at line 248 of file gnc-numeric.h. |
|
|
bitmasks for HOW flags. bits 8-15 of 'how' are reserved for the number of significant digits to use in the output with GNC_HOW_DENOM_SIGFIG Definition at line 163 of file gnc-numeric.h. |
|
|
An rational-number type. This is a rational number, defined by numerator and denominator. Definition at line 108 of file gnc-numeric.h. |
|
|
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 176 of file gnc-numeric.h. 00176 { 00178 GNC_HOW_RND_FLOOR = 0x01, 00179 00181 GNC_HOW_RND_CEIL = 0x02, 00182 00184 GNC_HOW_RND_TRUNC = 0x03, 00185 00187 GNC_HOW_RND_PROMOTE = 0x04, 00188 00192 GNC_HOW_RND_ROUND_HALF_DOWN = 0x05, 00193 00197 GNC_HOW_RND_ROUND_HALF_UP = 0x06, 00198 00204 GNC_HOW_RND_ROUND = 0x07, 00205 00209 GNC_HOW_RND_NEVER = 0x08 00210 };
|
|
|
How to compute a denominator, or'ed into the "how" field.
Definition at line 213 of file gnc-numeric.h. 00213 { 00219 GNC_HOW_DENOM_EXACT = 0x10, 00220 00226 GNC_HOW_DENOM_REDUCE = 0x20, 00227 00231 GNC_HOW_DENOM_LCD = 0x30, 00232 00237 GNC_HOW_DENOM_FIXED = 0x40, 00238 00242 GNC_HOW_DENOM_SIGFIG = 0x50 00243 };
|
|
|
Error codes
Definition at line 252 of file gnc-numeric.h. 00252 { 00253 GNC_ERROR_OK = 0, 00254 GNC_ERROR_ARG = -1, 00255 GNC_ERROR_OVERFLOW = -2, 00258 GNC_ERROR_DENOM_DIFF = -3, 00259 00262 GNC_ERROR_REMAINDER = -4 00263 } GNCNumericErrorCode;
|
|
||||||||||||||||
|
Convert a floating-point number to a gnc_numeric. Both 'denom' and 'how' are used as in arithmetic, but GNC_DENOM_AUTO is not recognized; a denominator must be specified either explicitctly or through sigfigs. Definition at line 999 of file gnc-numeric.c. 01000 { 01001 gnc_numeric out; 01002 gint64 int_part=0; 01003 double frac_part; 01004 gint64 frac_int=0; 01005 double logval; 01006 double sigfigs; 01007 01008 if((denom == GNC_DENOM_AUTO) && (how & GNC_HOW_DENOM_SIGFIG)) 01009 { 01010 if(fabs(in) < 10e-20) { 01011 logval = 0; 01012 } 01013 else { 01014 logval = log10(fabs(in)); 01015 logval = ((logval > 0.0) ? 01016 (floor(logval)+1.0) : (ceil(logval))); 01017 } 01018 sigfigs = GNC_HOW_GET_SIGFIGS(how); 01019 if(sigfigs-logval >= 0) { 01020 denom = (gint64)(pow(10, sigfigs-logval)); 01021 } 01022 else { 01023 denom = -((gint64)(pow(10, logval-sigfigs))); 01024 } 01025 01026 how = how & ~GNC_HOW_DENOM_SIGFIG & ~GNC_NUMERIC_SIGFIGS_MASK; 01027 } 01028 01029 int_part = (gint64)(floor(fabs(in))); 01030 frac_part = in - (double)int_part; 01031 01032 int_part = int_part * denom; 01033 frac_part = frac_part * (double)denom; 01034 01035 switch(how & GNC_NUMERIC_RND_MASK) { 01036 case GNC_HOW_RND_FLOOR: 01037 frac_int = (gint64)floor(frac_part); 01038 break; 01039 01040 case GNC_HOW_RND_CEIL: 01041 frac_int = (gint64)ceil(frac_part); 01042 break; 01043 01044 case GNC_HOW_RND_TRUNC: 01045 frac_int = (gint64)frac_part; 01046 break; 01047 01048 case GNC_HOW_RND_ROUND: 01049 case GNC_HOW_RND_ROUND_HALF_UP: 01050 frac_int = (gint64)rint(frac_part); 01051 break; 01052 01053 case GNC_HOW_RND_NEVER: 01054 frac_int = (gint64)floor(frac_part); 01055 if(frac_part != (double) frac_int) { 01056 /* signal an error */ 01057 } 01058 break; 01059 } 01060 01061 out.num = int_part + frac_int; 01062 out.denom = denom; 01063 return out; 01064 }
|
|
|
Convert to string. Uses a static, non-thread-safe buffer. For internal use only. Definition at line 1195 of file gnc-numeric.c. 01196 { 01197 static char buff[1000]; 01198 static char *p = buff; 01199 gint64 tmpnum = n.num; 01200 gint64 tmpdenom = n.denom; 01201 01202 p+= 100; 01203 if (p-buff >= 1000) p = buff; 01204 01205 sprintf(p, "%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, tmpnum, tmpdenom); 01206 01207 return p; 01208 }
|
|
|
Return the absolute value of the argument Definition at line 702 of file gnc-numeric.c. 00703 { 00704 if(gnc_numeric_check(a)) { 00705 return gnc_numeric_error(GNC_ERROR_ARG); 00706 } 00707 return gnc_numeric_create(ABS(a.num), a.denom); 00708 }
|
|
||||||||||||||||||||
|
Return a+b. Definition at line 327 of file gnc-numeric.c. 00329 { 00330 gnc_numeric sum; 00331 00332 if(gnc_numeric_check(a) || gnc_numeric_check(b)) 00333 { 00334 return gnc_numeric_error(GNC_ERROR_ARG); 00335 } 00336 00337 if((denom == GNC_DENOM_AUTO) && 00338 (how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_FIXED) 00339 { 00340 if(a.denom == b.denom) { 00341 denom = a.denom; 00342 } 00343 else if(b.num == 0) { 00344 denom = a.denom; 00345 b.denom = a.denom; 00346 } 00347 else if(a.num == 0) { 00348 denom = b.denom; 00349 a.denom = b.denom; 00350 } 00351 else { 00352 return gnc_numeric_error(GNC_ERROR_DENOM_DIFF); 00353 } 00354 } 00355 00356 if(a.denom < 0) 00357 { 00358 a.num *= a.denom; 00359 a.denom = 1; 00360 } 00361 00362 if(b.denom < 0) 00363 { 00364 b.num *= b.denom; 00365 b.denom = 1; 00366 } 00367 00368 /* Get an exact answer.. same denominator is the common case. */ 00369 if(a.denom == b.denom) 00370 { 00371 sum.num = a.num + b.num; 00372 sum.denom = a.denom; 00373 } 00374 else 00375 { 00376 /* We want to do this: 00377 * sum.num = a.num*b.denom + b.num*a.denom; 00378 * sum.denom = a.denom*b.denom; 00379 * but the multiply could overflow. 00380 * Computing the LCD minimizes likelyhood of overflow 00381 */ 00382 gint64 lcd; 00383 qofint128 ca, cb, cab; 00384 lcd = gnc_numeric_lcd(a,b); 00385 if (GNC_ERROR_ARG == lcd) 00386 { 00387 return gnc_numeric_error(GNC_ERROR_OVERFLOW); 00388 } 00389 ca = mult128 (a.num, lcd/a.denom); 00390 if (ca.isbig) return gnc_numeric_error(GNC_ERROR_OVERFLOW); 00391 00392 cb = mult128 (b.num, lcd/b.denom); 00393 if (cb.isbig) return gnc_numeric_error(GNC_ERROR_OVERFLOW); 00394 00395 cab = add128 (ca, cb); 00396 if (cab.isbig) return gnc_numeric_error(GNC_ERROR_OVERFLOW); 00397 00398 sum.num = cab.lo; 00399 if (cab.isneg) sum.num = -sum.num; 00400 sum.denom = lcd; 00401 } 00402 00403 if((denom == GNC_DENOM_AUTO) && 00404 ((how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_LCD)) 00405 { 00406 denom = gnc_numeric_lcd(a, b); 00407 how = how & GNC_NUMERIC_RND_MASK; 00408 } 00409 00410 return gnc_numeric_convert(sum, denom, how); 00411 }
|
|
||||||||||||
|
Shortcut for common case: gnc_numeric_add(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_FIXED | GNC_HOW_RND_NEVER); Definition at line 426 of file gnc-numeric.h. 00426 { 00427 return gnc_numeric_add(a, b, GNC_DENOM_AUTO, 00428 GNC_HOW_DENOM_FIXED | GNC_HOW_RND_NEVER); 00429 }
|
|
||||||||||||||||||||||||
|
The same as gnc_numeric_add, but uses 'error' for accumulating conversion roundoff error. Definition at line 1099 of file gnc-numeric.c. 01102 { 01103 01104 gnc_numeric sum = gnc_numeric_add(a, b, denom, how); 01105 gnc_numeric exact = gnc_numeric_add(a, b, GNC_DENOM_AUTO, 01106 GNC_HOW_DENOM_REDUCE); 01107 gnc_numeric err = gnc_numeric_sub(sum, exact, GNC_DENOM_AUTO, 01108 GNC_HOW_DENOM_REDUCE); 01109 01110 if(error) { 01111 *error = err; 01112 } 01113 return sum; 01114 }
|
|
|
Check for error signal in value. Returns GNC_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 58 of file gnc-numeric.c. 00059 { 00060 if(in.denom != 0) 00061 { 00062 return GNC_ERROR_OK; 00063 } 00064 else if(in.num) 00065 { 00066 if ((0 < in.num) || (-4 > in.num)) 00067 { 00068 in.num = (gint64) GNC_ERROR_OVERFLOW; 00069 } 00070 return (GNCNumericErrorCode) in.num; 00071 } 00072 else 00073 { 00074 return GNC_ERROR_ARG; 00075 } 00076 }
|
|
||||||||||||
|
Returns 1 if a>b, -1 if b>a, 0 if a == b Definition at line 221 of file gnc-numeric.c. 00222 { 00223 gint64 aa, bb; 00224 qofint128 l, r; 00225 00226 if(gnc_numeric_check(a) || gnc_numeric_check(b)) 00227 { 00228 return 0; 00229 } 00230 00231 if (a.denom == b.denom) 00232 { 00233 if(a.num == b.num) return 0; 00234 if(a.num > b.num) return 1; 00235 return -1; 00236 } 00237 00238 if ((a.denom > 0) && (b.denom > 0)) 00239 { 00240 /* Avoid overflows using 128-bit intermediate math */ 00241 l = mult128 (a.num, b.denom); 00242 r = mult128 (b.num, a.denom); 00243 return cmp128 (l,r); 00244 } 00245 00246 aa = a.num * a.denom; 00247 bb = b.num * b.denom; 00248 00249 if(aa == bb) return 0; 00250 if(aa > bb) return 1; 00251 return -1; 00252 }
|
|
||||||||||||||||
|
Change the denominator of a gnc_numeric value to the specified denominator under standard arguments 'denom' and 'how'. Definition at line 715 of file gnc-numeric.c. 00716 { 00717 gnc_numeric out; 00718 gnc_numeric temp; 00719 gint64 temp_bc; 00720 gint64 temp_a; 00721 gint64 remainder; 00722 gint64 sign; 00723 gint denom_neg=0; 00724 double ratio, logratio; 00725 double sigfigs; 00726 qofint128 nume, newm; 00727 00728 temp.num = 0; 00729 temp.denom = 0; 00730 00731 if(gnc_numeric_check(in)) { 00732 return gnc_numeric_error(GNC_ERROR_ARG); 00733 } 00734 00735 if(denom == GNC_DENOM_AUTO) 00736 { 00737 switch(how & GNC_NUMERIC_DENOM_MASK) 00738 { 00739 default: 00740 case GNC_HOW_DENOM_LCD: /* LCD is meaningless with AUTO in here */ 00741 case GNC_HOW_DENOM_EXACT: 00742 return in; 00743 break; 00744 00745 case GNC_HOW_DENOM_REDUCE: 00746 /* reduce the input to a relatively-prime fraction */ 00747 return gnc_numeric_reduce(in); 00748 break; 00749 00750 case GNC_HOW_DENOM_FIXED: 00751 if(in.denom != denom) { 00752 return gnc_numeric_error(GNC_ERROR_DENOM_DIFF); 00753 } 00754 else { 00755 return in; 00756 } 00757 break; 00758 00759 case GNC_HOW_DENOM_SIGFIG: 00760 ratio = fabs(gnc_numeric_to_double(in)); 00761 if(ratio < 10e-20) { 00762 logratio = 0; 00763 } 00764 else { 00765 logratio = log10(ratio); 00766 logratio = ((logratio > 0.0) ? 00767 (floor(logratio)+1.0) : (ceil(logratio))); 00768 } 00769 sigfigs = GNC_HOW_GET_SIGFIGS(how); 00770 00771 if(sigfigs-logratio >= 0) { 00772 denom = (gint64)(pow(10, sigfigs-logratio)); 00773 } 00774 else { 00775 denom = -((gint64)(pow(10, logratio-sigfigs))); 00776 } 00777 00778 how = how & ~GNC_HOW_DENOM_SIGFIG & ~GNC_NUMERIC_SIGFIGS_MASK; 00779 break; 00780 00781 } 00782 } 00783 00784 /* Make sure we need to do the work */ 00785 if(in.denom == denom) { 00786 return in; 00787 } 00788 00789 /* If the denominator of the input value is negative, get rid of that. */ 00790 if(in.denom < 0) { 00791 in.num = in.num * (- in.denom); 00792 in.denom = 1; 00793 } 00794 00795 sign = (in.num < 0) ? -1 : 1; 00796 00797 /* If the denominator is less than zero, we are to interpret it as 00798 * the reciprocal of its magnitude. */ 00799 if(denom < 0) 00800 { 00801 00802 /* XXX FIXME: use 128-bit math here ... */ 00803 denom = - denom; 00804 denom_neg = 1; 00805 temp_a = (in.num < 0) ? -in.num : in.num; 00806 temp_bc = in.denom * denom; 00807 remainder = in.num % temp_bc; 00808 out.num = in.num / temp_bc; 00809 out.denom = - denom; 00810 } 00811 else 00812 { 00813 /* Do all the modulo and int division on positive values to make 00814 * things a little clearer. Reduce the fraction denom/in.denom to 00815 * help with range errors */ 00816 temp.num = denom; 00817 temp.denom = in.denom; 00818 temp = gnc_numeric_reduce(temp); 00819 00820 /* Symbolically, do the following: 00821 * out.num = in.num * temp.num; 00822 * remainder = out.num % temp.denom; 00823 * out.num = out.num / temp.denom; 00824 * out.denom = denom; 00825 */ 00826 nume = mult128 (in.num, temp.num); 00827 newm = div128 (nume, temp.denom); 00828 remainder = rem128 (nume, temp.denom); 00829 00830 if (newm.isbig) 00831 { 00832 return gnc_numeric_error(GNC_ERROR_OVERFLOW); 00833 } 00834 00835 out.num = newm.lo; 00836 out.denom = denom; 00837 } 00838 00839 if (remainder) 00840 { 00841 switch(how & GNC_NUMERIC_RND_MASK) 00842 { 00843 case GNC_HOW_RND_FLOOR: 00844 if(sign < 0) { 00845 out.num = out.num + 1; 00846 } 00847 break; 00848 00849 case GNC_HOW_RND_CEIL: 00850 if(sign > 0) { 00851 out.num = out.num + 1; 00852 } 00853 break; 00854 00855 case GNC_HOW_RND_TRUNC: 00856 break; 00857 00858 case GNC_HOW_RND_PROMOTE: 00859 out.num = out.num + 1; 00860 break; 00861 00862 case GNC_HOW_RND_ROUND_HALF_DOWN: 00863 if(denom_neg) 00864 { 00865 if((2 * remainder) > in.denom*denom) 00866 { 00867 out.num = out.num + 1; 00868 } 00869 } 00870 else if((2 * remainder) > temp.denom) 00871 { 00872 out.num = out.num + 1; 00873 } 00874 /* check that 2*remainder didn't over-flow */ 00875 else if (((2 * remainder) < remainder) && 00876 (remainder > (temp.denom / 2))) 00877 { 00878 out.num = out.num + 1; 00879 } 00880 break; 00881 00882 case GNC_HOW_RND_ROUND_HALF_UP: 00883 if(denom_neg) 00884 { 00885 if((2 * remainder) >= in.denom*denom) 00886 { 00887 out.num = out.num + 1; 00888 } 00889 } 00890 else if((2 * remainder ) >= temp.denom) 00891 { 00892 out.num = out.num + 1; 00893 } 00894 /* check that 2*remainder didn't over-flow */ 00895 else if (((2 * remainder) < remainder) && 00896 (remainder >= (temp.denom / 2))) 00897 { 00898 out.num = out.num + 1; 00899 } 00900 break; 00901 00902 case GNC_HOW_RND_ROUND: 00903 if(denom_neg) 00904 { 00905 if((2 * remainder) > in.denom*denom) 00906 { 00907 out.num = out.num + 1; 00908 } 00909 else if((2 * remainder) == in.denom*denom) 00910 { 00911 if(out.num % 2) 00912 { 00913 out.num = out.num + 1; 00914 } 00915 } 00916 } 00917 else 00918 { 00919 if((2 * remainder ) > temp.denom) 00920 { 00921 out.num = out.num + 1; 00922 } 00923 /* check that 2*remainder didn't over-flow */ 00924 else if (((2 * remainder) < remainder) && 00925 (remainder > (temp.denom / 2))) 00926 { 00927 out.num = out.num + 1; 00928 } 00929 else if((2 * remainder) == temp.denom) 00930 { 00931 if(out.num % 2) 00932 { 00933 out.num = out.num + 1; 00934 } 00935 } 00936 /* check that 2*remainder didn't over-flow */ 00937 else if (((2 * remainder) < remainder) && 00938 (remainder == (temp.denom / 2))) 00939 { 00940 if(out.num % 2) 00941 { 00942 out.num = out.num + 1; 00943 } 00944 } 00945 } 00946 break; 00947 00948 case GNC_HOW_RND_NEVER: 00949 return gnc_numeric_error(GNC_ERROR_REMAINDER); 00950 break; 00951 } 00952 } 00953 00954 out.num = (sign > 0) ? out.num : (-out.num); 00955 00956 return out; 00957 }
|
|
||||||||||||||||||||
|
Same as gnc_numeric_convert, but return a remainder value for accumulating conversion error. |
|
||||||||||||
|
Make a gnc_numeric from numerator and denominator Definition at line 287 of file gnc-numeric.h. 00287 { 00288 gnc_numeric out; 00289 out.num = num; 00290 out.denom = denom; 00291 return out; 00292 }
|
|
|
Return denominator Definition at line 325 of file gnc-numeric.h. 00325 { return a.denom; }
|
|
||||||||||||||||||||
|
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 556 of file gnc-numeric.c. 00558 { 00559 gnc_numeric quotient; 00560 qofint128 nume, deno; 00561 00562 if(gnc_numeric_check(a) || gnc_numeric_check(b)) 00563 { 00564 return gnc_numeric_error(GNC_ERROR_ARG); 00565 } 00566 00567 if((denom == GNC_DENOM_AUTO) && 00568 (how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_FIXED) 00569 { 00570 if(a.denom == b.denom) 00571 { 00572 denom = a.denom; 00573 } 00574 else if(a.denom == 0) 00575 { 00576 denom = b.denom; 00577 } 00578 else 00579 { 00580 return gnc_numeric_error(GNC_ERROR_DENOM_DIFF); 00581 } 00582 } 00583 00584 00585 if(a.denom < 0) 00586 { 00587 a.num *= a.denom; 00588 a.denom = 1; 00589 } 00590 00591 if(b.denom < 0) 00592 { 00593 b.num *= b.denom; 00594 b.denom = 1; 00595 } 00596 00597 if(a.denom == b.denom) 00598 { 00599 quotient.num = a.num; 00600 quotient.denom = b.num; 00601 } 00602 else 00603 { 00604 gint64 sgn = 1; 00605 if (0 > a.num) 00606 { 00607 sgn = -sgn; 00608 a.num = -a.num; 00609 } 00610 if (0 > b.num) 00611 { 00612 sgn = -sgn; 00613 b.num = -b.num; 00614 } 00615 nume = mult128(a.num, b.denom); 00616 deno = mult128(b.num, a.denom); 00617 00618 /* Try to avoid overflow by removing common factors */ 00619 if (nume.isbig && deno.isbig) 00620 { 00621 gnc_numeric ra = gnc_numeric_reduce (a); 00622 gnc_numeric rb = gnc_numeric_reduce (b); 00623 00624 gint64 gcf_nume = gcf64(ra.num, rb.num); 00625 gint64 gcf_deno = gcf64(rb.denom, ra.denom); 00626 nume = mult128(ra.num/gcf_nume, rb.denom/gcf_deno); 00627 deno = mult128(rb.num/gcf_nume, ra.denom/gcf_deno); 00628 } 00629 00630 if ((0 == nume.isbig) && (0 == deno.isbig)) 00631 { 00632 quotient.num = sgn * nume.lo; 00633 quotient.denom = deno.lo; 00634 goto dive_done; 00635 } 00636 else if (0 == deno.isbig) 00637 { 00638 quotient = reduce128 (nume, deno.lo); 00639 if (0 == gnc_numeric_check (quotient)) 00640 { 00641 quotient.num *= sgn; 00642 goto dive_done; 00643 } 00644 } 00645 00646 /* If rounding allowed, then shift until there's no 00647 * more overflow. The conversion at the end will fix 00648 * things up for the final value. */ 00649 if ((how & GNC_NUMERIC_RND_MASK) == GNC_HOW_RND_NEVER) 00650 { 00651 return gnc_numeric_error (GNC_ERROR_OVERFLOW); 00652 } 00653 while (nume.isbig || deno.isbig) 00654 { 00655 nume = shift128 (nume); 00656 deno = shift128 (deno); 00657 } 00658 quotient.num = sgn * nume.lo; 00659 quotient.denom = deno.lo; 00660 if (0 == quotient.denom) 00661 { 00662 return gnc_numeric_error (GNC_ERROR_OVERFLOW); 00663 } 00664 } 00665 00666 if(quotient.denom < 0) 00667 { 00668 quotient.num = -quotient.num; 00669 quotient.denom = -quotient.denom; 00670 } 00671 00672 dive_done: 00673 if((denom == GNC_DENOM_AUTO) && 00674 ((how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_LCD)) 00675 { 00676 denom = gnc_numeric_lcd(a, b); 00677 how = how & GNC_NUMERIC_RND_MASK; 00678 } 00679 00680 return gnc_numeric_convert(quotient, denom, how); 00681 }
|
|
||||||||||||||||||||||||
|
The same as gnc_numeric_div, but uses error for accumulating conversion roundoff error. Definition at line 1163 of file gnc-numeric.c. 01166 { 01167 gnc_numeric quot = gnc_numeric_div(a, b, denom, how); 01168 gnc_numeric exact = gnc_numeric_div(a, b, GNC_DENOM_AUTO, 01169 GNC_HOW_DENOM_REDUCE); 01170 gnc_numeric err = gnc_numeric_sub(quot, exact, 01171 GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE); 01172 if(error) { 01173 *error = err; 01174 } 01175 return quot; 01176 }
|
|
||||||||||||
|
Equivalence predicate: Returns TRUE (1) if a and b are exactly the same (have the same numerator and denominator) Definition at line 260 of file gnc-numeric.c.
|
|
||||||||||||
|
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 271 of file gnc-numeric.c. 00272 { 00273 if ((a.denom == b.denom) && (a.denom > 0)) 00274 { 00275 return (a.num == b.num); 00276 } 00277 if ((a.denom > 0) && (b.denom > 0)) 00278 { 00279 // return (a.num*b.denom == b.num*a.denom); 00280 qofint128 l = mult128 (a.num, b.denom); 00281 qofint128 r = mult128 (b.num, a.denom); 00282 return equal128 (l, r); 00283 00284 #if ALT_WAY_OF_CHECKING_EQUALITY 00285 gnc_numeric ra = gnc_numeric_reduce (a); 00286 gnc_numeric rb = gnc_numeric_reduce (b); 00287 if (ra.denom != rb.denom) return 0; 00288 if (ra.num != rb.num) return 0; 00289 return 1; 00290 #endif 00291 } 00292 if ((a.denom < 0) && (b.denom < 0)) 00293 { 00294 return ((a.num * b.denom) == (a.denom * b.num)); 00295 } 00296 else 00297 { 00298 return 0; 00299 } 00300 }
|
|
|
Create a gnc_numeric object that signals the error condition noted by error_code, rather than a number. Definition at line 1088 of file gnc-numeric.c. 01089 { 01090 return gnc_numeric_create(error_code, 0LL); 01091 }
|
|
||||||||||||||||||||
|
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 437 of file gnc-numeric.c. 00439 { 00440 gnc_numeric product, result; 00441 qofint128 bignume, bigdeno; 00442 00443 if(gnc_numeric_check(a) || gnc_numeric_check(b)) { 00444 return gnc_numeric_error(GNC_ERROR_ARG); 00445 } 00446 00447 if((denom == GNC_DENOM_AUTO) && 00448 (how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_FIXED) { 00449 if(a.denom == b.denom) { 00450 denom = a.denom; 00451 } 00452 else if(b.num == 0) { 00453 denom = a.denom; 00454 } 00455 else if(a.num == 0) { 00456 denom = b.denom; 00457 } 00458 else { 00459 return gnc_numeric_error(GNC_ERROR_DENOM_DIFF); 00460 } 00461 } 00462 00463 if((denom == GNC_DENOM_AUTO) && 00464 ((how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_LCD)) 00465 { 00466 denom = gnc_numeric_lcd(a, b); 00467 how = how & GNC_NUMERIC_RND_MASK; 00468 } 00469 00470 if(a.denom < 0) { 00471 a.num *= a.denom; 00472 a.denom = 1; 00473 } 00474 00475 if(b.denom < 0) { 00476 b.num *= b.denom; 00477 b.denom = 1; 00478 } 00479 00480 bignume = mult128 (a.num, b.num); 00481 bigdeno = mult128 (a.denom, b.denom); 00482 product.num = a.num*b.num; 00483 product.denom = a.denom*b.denom; 00484 00485 /* If it looks to be overflowing, try to reduce the fraction ... */ 00486 if (bignume.isbig || bigdeno.isbig) 00487 { 00488 gint64 tmp; 00489 a = gnc_numeric_reduce (a); 00490 b = gnc_numeric_reduce (b); 00491 tmp = a.num; 00492 a.num = b.num; 00493 b.num = tmp; 00494 a = gnc_numeric_reduce (a); 00495 b = gnc_numeric_reduce (b); 00496 00497 bignume = mult128 (a.num, b.num); 00498 bigdeno = mult128 (a.denom, b.denom); 00499 product.num = a.num*b.num; 00500 product.denom = a.denom*b.denom; 00501 } 00502 00503 /* If it its still overflowing, and rounding is allowed then round */ 00504 if (bignume.isbig || bigdeno.isbig) 00505 { 00506 /* If rounding allowed, then shift until there's no 00507 * more overflow. The conversion at the end will fix 00508 * things up for the final value. Else overflow. */ 00509 if ((how & GNC_NUMERIC_RND_MASK) == GNC_HOW_RND_NEVER) 00510 { 00511 if (bigdeno.isbig) 00512 { 00513 return gnc_numeric_error (GNC_ERROR_OVERFLOW); 00514 } 00515 product = reduce128 (bignume, product.denom); 00516 if (gnc_numeric_check (product)) 00517 { 00518 return gnc_numeric_error (GNC_ERROR_OVERFLOW); 00519 } 00520 } 00521 else 00522 { 00523 while (bignume.isbig || bigdeno.isbig) 00524 { 00525 bignume = shift128 (bignume); 00526 bigdeno = shift128 (bigdeno); 00527 } 00528 product.num = bignume.lo; 00529 if (bignume.isneg) product.num = -product.num; 00530 00531 product.denom = bigdeno.lo; 00532 if (0 == product.denom) 00533 { 00534 return gnc_numeric_error (GNC_ERROR_OVERFLOW); 00535 } 00536 } 00537 } 00538 00539 #if 0 /* currently, product denom won't ever be zero */ 00540 if(product.denom < 0) { 00541 product.num = -product.num; 00542 product.denom = -product.denom; 00543 } 00544 #endif 00545 00546 result = gnc_numeric_convert(product, denom, how); 00547 return result; 00548 }
|
|
||||||||||||||||||||||||
|
The same as gnc_numeric_mul, but uses error for accumulating conversion roundoff error. Definition at line 1142 of file gnc-numeric.c. 01145 { 01146 gnc_numeric prod = gnc_numeric_mul(a, b, denom, how); 01147 gnc_numeric exact = gnc_numeric_mul(a, b, GNC_DENOM_AUTO, 01148 GNC_HOW_DENOM_REDUCE); 01149 gnc_numeric err = gnc_numeric_sub(prod, exact, GNC_DENOM_AUTO, 01150 GNC_HOW_DENOM_REDUCE); 01151 if(error) { 01152 *error = err; 01153 } 01154 return prod; 01155 }
|
|
|
Negate the argument Definition at line 689 of file gnc-numeric.c. 00689 { 00690 if(gnc_numeric_check(a)) { 00691 return gnc_numeric_error(GNC_ERROR_ARG); 00692 } 00693 return gnc_numeric_create(- a.num, a.denom); 00694 }
|
|
|
Returns 1 if a < 0, otherwise returns 0. Definition at line 172 of file gnc-numeric.c. 00173 { 00174 if(gnc_numeric_check(a)) 00175 { 00176 return 0; 00177 } 00178 else 00179 { 00180 if((a.num < 0) && (a.denom != 0)) 00181 { 00182 return 1; 00183 } 00184 else 00185 { 00186 return 0; 00187 } 00188 } 00189 }
|
|
|
Return numerator Definition at line 322 of file gnc-numeric.h. 00322 { return a.num; }
|
|
|
Returns 1 if a > 0, otherwise returns 0. Definition at line 196 of file gnc-numeric.c. 00197 { 00198 if(gnc_numeric_check(a)) 00199 { 00200 return 0; 00201 } 00202 else 00203 { 00204 if((a.num > 0) && (a.denom != 0)) 00205 { 00206 return 1; 00207 } 00208 else 00209 { 00210 return 0; 00211 } 00212 } 00213 }
|
|
|
Return input after reducing it by Greated Common Factor (GCF) elimination Definition at line 967 of file gnc-numeric.c. 00968 { 00969 gint64 t; 00970 gint64 num = (in.num < 0) ? (- in.num) : in.num ; 00971 gint64 denom = in.denom; 00972 gnc_numeric out; 00973 00974 if(gnc_numeric_check(in)) 00975 { 00976 return gnc_numeric_error(GNC_ERROR_ARG); 00977 } 00978 00979 /* The strategy is to use Euclid's algorithm */ 00980 while (denom > 0) { 00981 t = num % denom; 00982 num = denom; 00983 denom = t; 00984 } 00985 /* num now holds the GCD (Greatest Common Divisor) */ 00986 00987 /* All calculations are done on positive num, since it's not 00988 * well defined what % does for negative values */ 00989 out.num = in.num / num; 00990 out.denom = in.denom / num; 00991 return out; 00992 }
|
|
||||||||||||||||||||
|
Equivalence predicate: Convert both a and b to denom using the specified DENOM and method HOW, and compare numerators the results using gnc_numeric_equal. For example, if a == 7/16 and b == 3/4, gnc_numeric_same(a, b, 2, GNC_HOW_RND_TRUNC) == 1 because both 7/16 and 3/4 round to 1/2 under truncation. However, gnc_numeric_same(a, b, 2, GNC_HOW_RND_ROUND) == 0 because 7/16 rounds to 1/2 under unbiased rounding but 3/4 rounds to 2/2. Definition at line 310 of file gnc-numeric.c. 00311 { 00312 gnc_numeric aconv, bconv; 00313 00314 aconv = gnc_numeric_convert(a, denom, how); 00315 bconv = gnc_numeric_convert(b, denom, how); 00316 00317 return(gnc_numeric_equal(aconv, bconv)); 00318 }
|
|
||||||||||||||||||||
|
Return a-b. Definition at line 418 of file gnc-numeric.c. 00420 { 00421 gnc_numeric nb; 00422 if(gnc_numeric_check(a) || gnc_numeric_check(b)) 00423 { 00424 return gnc_numeric_error(GNC_ERROR_ARG); 00425 } 00426 00427 nb = b; 00428 nb.num = -nb.num; 00429 return gnc_numeric_add (a, nb, denom, how); 00430 }
|
|
||||||||||||
|
Shortcut for most common case: gnc_numeric_sub(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_FIXED | GNC_HOW_RND_NEVER); Definition at line 436 of file gnc-numeric.h. 00436 { 00437 return gnc_numeric_sub(a, b, GNC_DENOM_AUTO, 00438 GNC_HOW_DENOM_FIXED | GNC_HOW_RND_NEVER); 00439 }
|
|
||||||||||||||||||||||||
|
The same as gnc_numeric_sub, but uses error for accumulating conversion roundoff error. Definition at line 1121 of file gnc-numeric.c. 01124 { 01125 gnc_numeric diff = gnc_numeric_sub(a, b, denom, how); 01126 gnc_numeric exact = gnc_numeric_sub(a, b, GNC_DENOM_AUTO, 01127 GNC_HOW_DENOM_REDUCE); 01128 gnc_numeric err = gnc_numeric_sub(diff, exact, GNC_DENOM_AUTO, 01129 GNC_HOW_DENOM_REDUCE); 01130 if(error) { 01131 *error = err; 01132 } 01133 return diff; 01134 }
|
|
|
Convert numeric to floating-point value. Definition at line 1071 of file gnc-numeric.c. 01072 { 01073 if(in.denom > 0) 01074 { 01075 return (double)in.num/(double)in.denom; 01076 } 01077 else 01078 { 01079 return (double)(in.num * in.denom); 01080 } 01081 }
|
|
|
Convert to string. The returned buffer is to be g_free'd by the caller (it was allocated through g_strdup) Definition at line 1183 of file gnc-numeric.c. 01184 { 01185 gchar *result; 01186 gint64 tmpnum = n.num; 01187 gint64 tmpdenom = n.denom; 01188 01189 result = g_strdup_printf("%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, tmpnum, tmpdenom); 01190 01191 return result; 01192 }
|
|
|
create a zero-value gnc_numeric Definition at line 296 of file gnc-numeric.h. 00296 { return gnc_numeric_create(0, 1); }
|
|
|
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0. Definition at line 148 of file gnc-numeric.c. 00149 { 00150 if(gnc_numeric_check(a)) 00151 { 00152 return 0; 00153 } 00154 else 00155 { 00156 if((a.num == 0) && (a.denom != 0)) 00157 { 00158 return 1; 00159 } 00160 else 00161 { 00162 return 0; 00163 } 00164 } 00165 }
|
|
||||||||||||
|
Read a gnc_numeric from str, skipping any leading whitespace. Return TRUE on success and store the resulting value in "n". Return NULL on error. Definition at line 1211 of file gnc-numeric.c. 01212 { 01213 size_t num_read; 01214 gint64 tmpnum; 01215 gint64 tmpdenom; 01216 01217 if(!str) return FALSE; 01218 01219 #ifdef GNC_DEPRECATED 01220 /* must use "<" here because %n's effects aren't well defined */ 01221 if(sscanf(str, " " GNC_SCANF_LLD "/" GNC_SCANF_LLD "%n", 01222 &tmpnum, &tmpdenom, &num_read) < 2) { 01223 return FALSE; 01224 } 01225 #else 01226 tmpnum = strtoll (str, NULL, 0); 01227 str = strchr (str, '/'); 01228 if (!str) return FALSE; 01229 str ++; 01230 tmpdenom = strtoll (str, NULL, 0); 01231 num_read = strspn (str, "0123456789"); 01232 #endif 01233 n->num = tmpnum; 01234 n->denom = tmpdenom; 01235 return TRUE; 01236 }
|
1.4.5