Copyright (C) 2004 Linas Vepstas <linas@linas.org>
Definition in file gnc-numeric.h.
Go to the source code of this file.
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) |
gdouble | 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) |
gint | 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) |
gint | 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 229 of file gnc-numeric.h. |
|
Use the value 1/n as the denominator of the output value. Definition at line 232 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 202 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 117 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 130 of file gnc-numeric.h. 00130 { 00132 GNC_HOW_RND_FLOOR = 0x01, 00133 00135 GNC_HOW_RND_CEIL = 0x02, 00136 00138 GNC_HOW_RND_TRUNC = 0x03, 00139 00141 GNC_HOW_RND_PROMOTE = 0x04, 00142 00146 GNC_HOW_RND_ROUND_HALF_DOWN = 0x05, 00147 00151 GNC_HOW_RND_ROUND_HALF_UP = 0x06, 00152 00158 GNC_HOW_RND_ROUND = 0x07, 00159 00163 GNC_HOW_RND_NEVER = 0x08 00164 };
|
|
How to compute a denominator, or'ed into the "how" field.
Definition at line 167 of file gnc-numeric.h. 00167 { 00173 GNC_HOW_DENOM_EXACT = 0x10, 00174 00180 GNC_HOW_DENOM_REDUCE = 0x20, 00181 00185 GNC_HOW_DENOM_LCD = 0x30, 00186 00191 GNC_HOW_DENOM_FIXED = 0x40, 00192 00196 GNC_HOW_DENOM_SIGFIG = 0x50 00197 };
|
|
Error codes
Definition at line 206 of file gnc-numeric.h. 00206 { 00207 GNC_ERROR_OK = 0, 00208 GNC_ERROR_ARG = -1, 00209 GNC_ERROR_OVERFLOW = -2, 00212 GNC_ERROR_DENOM_DIFF = -3, 00213 00216 GNC_ERROR_REMAINDER = -4 00217 } 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 1023 of file gnc-numeric.c. 01024 { 01025 gnc_numeric out; 01026 gint64 int_part=0; 01027 double frac_part; 01028 gint64 frac_int=0; 01029 double logval; 01030 double sigfigs; 01031 01032 if((denom == GNC_DENOM_AUTO) && (how & GNC_HOW_DENOM_SIGFIG)) 01033 { 01034 if(fabs(in) < 10e-20) { 01035 logval = 0; 01036 } 01037 else { 01038 logval = log10(fabs(in)); 01039 logval = ((logval > 0.0) ? 01040 (floor(logval)+1.0) : (ceil(logval))); 01041 } 01042 sigfigs = GNC_HOW_GET_SIGFIGS(how); 01043 if(sigfigs-logval >= 0) { 01044 denom = (gint64)(pow(10, sigfigs-logval)); 01045 } 01046 else { 01047 denom = -((gint64)(pow(10, logval-sigfigs))); 01048 } 01049 01050 how = how & ~GNC_HOW_DENOM_SIGFIG & ~GNC_NUMERIC_SIGFIGS_MASK; 01051 } 01052 01053 int_part = (gint64)(floor(fabs(in))); 01054 frac_part = in - (double)int_part; 01055 01056 int_part = int_part * denom; 01057 frac_part = frac_part * (double)denom; 01058 01059 switch(how & GNC_NUMERIC_RND_MASK) { 01060 case GNC_HOW_RND_FLOOR: 01061 frac_int = (gint64)floor(frac_part); 01062 break; 01063 01064 case GNC_HOW_RND_CEIL: 01065 frac_int = (gint64)ceil(frac_part); 01066 break; 01067 01068 case GNC_HOW_RND_TRUNC: 01069 frac_int = (gint64)frac_part; 01070 break; 01071 01072 case GNC_HOW_RND_ROUND: 01073 case GNC_HOW_RND_ROUND_HALF_UP: 01074 frac_int = (gint64)rint(frac_part); 01075 break; 01076 01077 case GNC_HOW_RND_NEVER: 01078 frac_int = (gint64)floor(frac_part); 01079 if(frac_part != (double) frac_int) { 01080 /* signal an error */ 01081 } 01082 break; 01083 } 01084 01085 out.num = int_part + frac_int; 01086 out.denom = denom; 01087 return out; 01088 }
|
|
Convert to string. Uses a static, non-thread-safe buffer. For internal use only. Definition at line 1219 of file gnc-numeric.c. 01220 { 01221 static char buff[1000]; 01222 static char *p = buff; 01223 gint64 tmpnum = n.num; 01224 gint64 tmpdenom = n.denom; 01225 01226 p+= 100; 01227 if (p-buff >= 1000) p = buff; 01228 01229 sprintf(p, "%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, tmpnum, tmpdenom); 01230 01231 return p; 01232 }
|
|
Return the absolute value of the argument Definition at line 721 of file gnc-numeric.c. 00722 { 00723 if(gnc_numeric_check(a)) { 00724 return gnc_numeric_error(GNC_ERROR_ARG); 00725 } 00726 return gnc_numeric_create(ABS(a.num), a.denom); 00727 }
|
|
Return a+b. Definition at line 346 of file gnc-numeric.c. 00348 { 00349 gnc_numeric sum; 00350 00351 if(gnc_numeric_check(a) || gnc_numeric_check(b)) 00352 { 00353 return gnc_numeric_error(GNC_ERROR_ARG); 00354 } 00355 00356 if((denom == GNC_DENOM_AUTO) && 00357 (how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_FIXED) 00358 { 00359 if(a.denom == b.denom) { 00360 denom = a.denom; 00361 } 00362 else if(b.num == 0) { 00363 denom = a.denom; 00364 b.denom = a.denom; 00365 } 00366 else if(a.num == 0) { 00367 denom = b.denom; 00368 a.denom = b.denom; 00369 } 00370 else { 00371 return gnc_numeric_error(GNC_ERROR_DENOM_DIFF); 00372 } 00373 } 00374 00375 if(a.denom < 0) 00376 { 00377 a.num *= -a.denom; /* BUG: overflow not handled. */ 00378 a.denom = 1; 00379 } 00380 00381 if(b.denom < 0) 00382 { 00383 b.num *= -b.denom; /* BUG: overflow not handled. */ 00384 b.denom = 1; 00385 } 00386 00387 /* Get an exact answer.. same denominator is the common case. */ 00388 if(a.denom == b.denom) 00389 { 00390 sum.num = a.num + b.num; /* BUG: overflow not handled. */ 00391 sum.denom = a.denom; 00392 } 00393 else 00394 { 00395 /* We want to do this: 00396 * sum.num = a.num*b.denom + b.num*a.denom; 00397 * sum.denom = a.denom*b.denom; 00398 * but the multiply could overflow. 00399 * Computing the LCD minimizes likelihood of overflow 00400 */ 00401 gint64 lcd; 00402 qofint128 ca, cb, cab; 00403 lcd = gnc_numeric_lcd(a,b); 00404 if (GNC_ERROR_ARG == lcd) 00405 { 00406 return gnc_numeric_error(GNC_ERROR_OVERFLOW); 00407 } 00408 ca = mult128 (a.num, lcd/a.denom); 00409 if (ca.isbig) return gnc_numeric_error(GNC_ERROR_OVERFLOW); 00410 00411 cb = mult128 (b.num, lcd/b.denom); 00412 if (cb.isbig) return gnc_numeric_error(GNC_ERROR_OVERFLOW); 00413 00414 cab = add128 (ca, cb); 00415 if (cab.isbig) return gnc_numeric_error(GNC_ERROR_OVERFLOW); 00416 00417 sum.num = cab.lo; 00418 if (cab.isneg) sum.num = -sum.num; 00419 sum.denom = lcd; 00420 } 00421 00422 if((denom == GNC_DENOM_AUTO) && 00423 ((how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_LCD)) 00424 { 00425 denom = gnc_numeric_lcd(a, b); 00426 how = how & GNC_NUMERIC_RND_MASK; 00427 } 00428 00429 return gnc_numeric_convert(sum, denom, how); 00430 }
|
|
Shortcut for common case: gnc_numeric_add(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_FIXED | GNC_HOW_RND_NEVER); Definition at line 380 of file gnc-numeric.h. 00380 { 00381 return gnc_numeric_add(a, b, GNC_DENOM_AUTO, 00382 GNC_HOW_DENOM_FIXED | GNC_HOW_RND_NEVER); 00383 }
|
|
The same as gnc_numeric_add, but uses 'error' for accumulating conversion roundoff error. Definition at line 1123 of file gnc-numeric.c. 01126 { 01127 01128 gnc_numeric sum = gnc_numeric_add(a, b, denom, how); 01129 gnc_numeric exact = gnc_numeric_add(a, b, GNC_DENOM_AUTO, 01130 GNC_HOW_DENOM_REDUCE); 01131 gnc_numeric err = gnc_numeric_sub(sum, exact, GNC_DENOM_AUTO, 01132 GNC_HOW_DENOM_REDUCE); 01133 01134 if(error) { 01135 *error = err; 01136 } 01137 return sum; 01138 }
|
|
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 if (a.denom < 0) 00247 a.denom *= -1; 00248 if (b.denom < 0) 00249 b.denom *= -1; 00250 00251 /* BUG: Possible overflow here.. Also, doesn't properly deal with 00252 * reciprocal denominators. 00253 */ 00254 aa = a.num * a.denom; 00255 bb = b.num * b.denom; 00256 00257 if(aa == bb) return 0; 00258 if(aa > bb) return 1; 00259 return -1; 00260 }
|
|
Change the denominator of a gnc_numeric value to the specified denominator under standard arguments 'denom' and 'how'. Definition at line 734 of file gnc-numeric.c. 00735 { 00736 gnc_numeric out; 00737 gnc_numeric temp; 00738 gint64 temp_bc; 00739 gint64 temp_a; 00740 gint64 remainder; 00741 gint64 sign; 00742 gint denom_neg=0; 00743 double ratio, logratio; 00744 double sigfigs; 00745 qofint128 nume, newm; 00746 00747 temp.num = 0; 00748 temp.denom = 0; 00749 00750 if(gnc_numeric_check(in)) { 00751 return gnc_numeric_error(GNC_ERROR_ARG); 00752 } 00753 00754 if(denom == GNC_DENOM_AUTO) 00755 { 00756 switch(how & GNC_NUMERIC_DENOM_MASK) 00757 { 00758 default: 00759 case GNC_HOW_DENOM_LCD: /* LCD is meaningless with AUTO in here */ 00760 case GNC_HOW_DENOM_EXACT: 00761 return in; 00762 break; 00763 00764 case GNC_HOW_DENOM_REDUCE: 00765 /* reduce the input to a relatively-prime fraction */ 00766 return gnc_numeric_reduce(in); 00767 break; 00768 00769 case GNC_HOW_DENOM_FIXED: 00770 if(in.denom != denom) { 00771 return gnc_numeric_error(GNC_ERROR_DENOM_DIFF); 00772 } 00773 else { 00774 return in; 00775 } 00776 break; 00777 00778 case GNC_HOW_DENOM_SIGFIG: 00779 ratio = fabs(gnc_numeric_to_double(in)); 00780 if(ratio < 10e-20) { 00781 logratio = 0; 00782 } 00783 else { 00784 logratio = log10(ratio); 00785 logratio = ((logratio > 0.0) ? 00786 (floor(logratio)+1.0) : (ceil(logratio))); 00787 } 00788 sigfigs = GNC_HOW_GET_SIGFIGS(how); 00789 00790 if(sigfigs-logratio >= 0) { 00791 denom = (gint64)(pow(10, sigfigs-logratio)); 00792 } 00793 else { 00794 denom = -((gint64)(pow(10, logratio-sigfigs))); 00795 } 00796 00797 how = how & ~GNC_HOW_DENOM_SIGFIG & ~GNC_NUMERIC_SIGFIGS_MASK; 00798 break; 00799 00800 } 00801 } 00802 00803 /* Make sure we need to do the work */ 00804 if(in.denom == denom) { 00805 return in; 00806 } 00807 if(in.num == 0) { 00808 out.num = 0; 00809 out.denom = denom; 00810 return out; 00811 } 00812 00813 /* If the denominator of the input value is negative, get rid of that. */ 00814 if(in.denom < 0) { 00815 in.num = in.num * (- in.denom); /* BUG: overflow not handled. */ 00816 in.denom = 1; 00817 } 00818 00819 sign = (in.num < 0) ? -1 : 1; 00820 00821 /* If the denominator is less than zero, we are to interpret it as 00822 * the reciprocal of its magnitude. */ 00823 if(denom < 0) 00824 { 00825 00826 /* XXX FIXME: use 128-bit math here ... */ 00827 denom = - denom; 00828 denom_neg = 1; 00829 temp_a = (in.num < 0) ? -in.num : in.num; 00830 temp_bc = in.denom * denom; /* BUG: overflow not handled. */ 00831 remainder = temp_a % temp_bc; 00832 out.num = temp_a / temp_bc; 00833 out.denom = - denom; 00834 } 00835 else 00836 { 00837 /* Do all the modulo and int division on positive values to make 00838 * things a little clearer. Reduce the fraction denom/in.denom to 00839 * help with range errors */ 00840 temp.num = denom; 00841 temp.denom = in.denom; 00842 temp = gnc_numeric_reduce(temp); 00843 00844 /* Symbolically, do the following: 00845 * out.num = in.num * temp.num; 00846 * remainder = out.num % temp.denom; 00847 * out.num = out.num / temp.denom; 00848 * out.denom = denom; 00849 */ 00850 nume = mult128 (in.num, temp.num); 00851 newm = div128 (nume, temp.denom); 00852 remainder = rem128 (nume, temp.denom); 00853 00854 if (newm.isbig) 00855 { 00856 return gnc_numeric_error(GNC_ERROR_OVERFLOW); 00857 } 00858 00859 out.num = newm.lo; 00860 out.denom = denom; 00861 } 00862 00863 if (remainder) 00864 { 00865 switch(how & GNC_NUMERIC_RND_MASK) 00866 { 00867 case GNC_HOW_RND_FLOOR: 00868 if(sign < 0) { 00869 out.num = out.num + 1; 00870 } 00871 break; 00872 00873 case GNC_HOW_RND_CEIL: 00874 if(sign > 0) { 00875 out.num = out.num + 1; 00876 } 00877 break; 00878 00879 case GNC_HOW_RND_TRUNC: 00880 break; 00881 00882 case GNC_HOW_RND_PROMOTE: 00883 out.num = out.num + 1; 00884 break; 00885 00886 case GNC_HOW_RND_ROUND_HALF_DOWN: 00887 if(denom_neg) 00888 { 00889 if((2 * remainder) > in.denom*denom) 00890 { 00891 out.num = out.num + 1; 00892 } 00893 } 00894 else if((2 * remainder) > temp.denom) 00895 { 00896 out.num = out.num + 1; 00897 } 00898 /* check that 2*remainder didn't over-flow */ 00899 else if (((2 * remainder) < remainder) && 00900 (remainder > (temp.denom / 2))) 00901 { 00902 out.num = out.num + 1; 00903 } 00904 break; 00905 00906 case GNC_HOW_RND_ROUND_HALF_UP: 00907 if(denom_neg) 00908 { 00909 if((2 * remainder) >= in.denom*denom) 00910 { 00911 out.num = out.num + 1; 00912 } 00913 } 00914 else if((2 * remainder ) >= temp.denom) 00915 { 00916 out.num = out.num + 1; 00917 } 00918 /* check that 2*remainder didn't over-flow */ 00919 else if (((2 * remainder) < remainder) && 00920 (remainder >= (temp.denom / 2))) 00921 { 00922 out.num = out.num + 1; 00923 } 00924 break; 00925 00926 case GNC_HOW_RND_ROUND: 00927 if(denom_neg) 00928 { 00929 if((2 * remainder) > in.denom*denom) 00930 { 00931 out.num = out.num + 1; 00932 } 00933 else if((2 * remainder) == in.denom*denom) 00934 { 00935 if(out.num % 2) 00936 { 00937 out.num = out.num + 1; 00938 } 00939 } 00940 } 00941 else 00942 { 00943 if((2 * remainder ) > temp.denom) 00944 { 00945 out.num = out.num + 1; 00946 } 00947 /* check that 2*remainder didn't over-flow */ 00948 else if (((2 * remainder) < remainder) && 00949 (remainder > (temp.denom / 2))) 00950 { 00951 out.num = out.num + 1; 00952 } 00953 else if((2 * remainder) == temp.denom) 00954 { 00955 if(out.num % 2) 00956 { 00957 out.num = out.num + 1; 00958 } 00959 } 00960 /* check that 2*remainder didn't over-flow */ 00961 else if (((2 * remainder) < remainder) && 00962 (remainder == (temp.denom / 2))) 00963 { 00964 if(out.num % 2) 00965 { 00966 out.num = out.num + 1; 00967 } 00968 } 00969 } 00970 break; 00971 00972 case GNC_HOW_RND_NEVER: 00973 return gnc_numeric_error(GNC_ERROR_REMAINDER); 00974 break; 00975 } 00976 } 00977 00978 out.num = (sign > 0) ? out.num : (-out.num); 00979 00980 return out; 00981 }
|
|
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 241 of file gnc-numeric.h. 00241 { 00242 gnc_numeric out; 00243 out.num = num; 00244 out.denom = denom; 00245 return out; 00246 }
|
|
Return denominator Definition at line 279 of file gnc-numeric.h. 00279 { 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 575 of file gnc-numeric.c. 00577 { 00578 gnc_numeric quotient; 00579 qofint128 nume, deno; 00580 00581 if(gnc_numeric_check(a) || gnc_numeric_check(b)) 00582 { 00583 return gnc_numeric_error(GNC_ERROR_ARG); 00584 } 00585 00586 if((denom == GNC_DENOM_AUTO) && 00587 (how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_FIXED) 00588 { 00589 if(a.denom == b.denom) 00590 { 00591 denom = a.denom; 00592 } 00593 else if(a.denom == 0) 00594 { 00595 denom = b.denom; 00596 } 00597 else 00598 { 00599 return gnc_numeric_error(GNC_ERROR_DENOM_DIFF); 00600 } 00601 } 00602 00603 00604 if(a.denom < 0) 00605 { 00606 a.num *= -a.denom; /* BUG: overflow not handled. */ 00607 a.denom = 1; 00608 } 00609 00610 if(b.denom < 0) 00611 { 00612 b.num *= -b.denom; /* BUG: overflow not handled. */ 00613 b.denom = 1; 00614 } 00615 00616 if(a.denom == b.denom) 00617 { 00618 quotient.num = a.num; 00619 quotient.denom = b.num; 00620 } 00621 else 00622 { 00623 gint64 sgn = 1; 00624 if (0 > a.num) 00625 { 00626 sgn = -sgn; 00627 a.num = -a.num; 00628 } 00629 if (0 > b.num) 00630 { 00631 sgn = -sgn; 00632 b.num = -b.num; 00633 } 00634 nume = mult128(a.num, b.denom); 00635 deno = mult128(b.num, a.denom); 00636 00637 /* Try to avoid overflow by removing common factors */ 00638 if (nume.isbig && deno.isbig) 00639 { 00640 gnc_numeric ra = gnc_numeric_reduce (a); 00641 gnc_numeric rb = gnc_numeric_reduce (b); 00642 00643 gint64 gcf_nume = gcf64(ra.num, rb.num); 00644 gint64 gcf_deno = gcf64(rb.denom, ra.denom); 00645 nume = mult128(ra.num/gcf_nume, rb.denom/gcf_deno); 00646 deno = mult128(rb.num/gcf_nume, ra.denom/gcf_deno); 00647 } 00648 00649 if ((0 == nume.isbig) && (0 == deno.isbig)) 00650 { 00651 quotient.num = sgn * nume.lo; 00652 quotient.denom = deno.lo; 00653 goto dive_done; 00654 } 00655 else if (0 == deno.isbig) 00656 { 00657 quotient = reduce128 (nume, deno.lo); 00658 if (0 == gnc_numeric_check (quotient)) 00659 { 00660 quotient.num *= sgn; 00661 goto dive_done; 00662 } 00663 } 00664 00665 /* If rounding allowed, then shift until there's no 00666 * more overflow. The conversion at the end will fix 00667 * things up for the final value. */ 00668 if ((how & GNC_NUMERIC_RND_MASK) == GNC_HOW_RND_NEVER) 00669 { 00670 return gnc_numeric_error (GNC_ERROR_OVERFLOW); 00671 } 00672 while (nume.isbig || deno.isbig) 00673 { 00674 nume = shift128 (nume); 00675 deno = shift128 (deno); 00676 } 00677 quotient.num = sgn * nume.lo; 00678 quotient.denom = deno.lo; 00679 if (0 == quotient.denom) 00680 { 00681 return gnc_numeric_error (GNC_ERROR_OVERFLOW); 00682 } 00683 } 00684 00685 if(quotient.denom < 0) 00686 { 00687 quotient.num = -quotient.num; 00688 quotient.denom = -quotient.denom; 00689 } 00690 00691 dive_done: 00692 if((denom == GNC_DENOM_AUTO) && 00693 ((how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_LCD)) 00694 { 00695 denom = gnc_numeric_lcd(a, b); 00696 how = how & GNC_NUMERIC_RND_MASK; 00697 } 00698 00699 return gnc_numeric_convert(quotient, denom, how); 00700 }
|
|
The same as gnc_numeric_div, but uses error for accumulating conversion roundoff error. Definition at line 1187 of file gnc-numeric.c. 01190 { 01191 gnc_numeric quot = gnc_numeric_div(a, b, denom, how); 01192 gnc_numeric exact = gnc_numeric_div(a, b, GNC_DENOM_AUTO, 01193 GNC_HOW_DENOM_REDUCE); 01194 gnc_numeric err = gnc_numeric_sub(quot, exact, 01195 GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE); 01196 if(error) { 01197 *error = err; 01198 } 01199 return quot; 01200 }
|
|
Equivalence predicate: Returns TRUE (1) if a and b are exactly the same (have the same numerator and denominator) Definition at line 268 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 279 of file gnc-numeric.c. 00280 { 00281 qofint128 l, r; 00282 if ((a.denom == b.denom) && (a.denom > 0)) 00283 { 00284 return (a.num == b.num); 00285 } 00286 if ((a.denom > 0) && (b.denom > 0)) 00287 { 00288 // return (a.num*b.denom == b.num*a.denom); 00289 l = mult128 (a.num, b.denom); 00290 r = mult128 (b.num, a.denom); 00291 return equal128 (l, r); 00292 00293 #if ALT_WAY_OF_CHECKING_EQUALITY 00294 gnc_numeric ra = gnc_numeric_reduce (a); 00295 gnc_numeric rb = gnc_numeric_reduce (b); 00296 if (ra.denom != rb.denom) return 0; 00297 if (ra.num != rb.num) return 0; 00298 return 1; 00299 #endif 00300 } 00301 if ((a.denom < 0) && (b.denom < 0)) { 00302 l = mult128 (a.num, -a.denom); 00303 r = mult128 (b.num, -b.denom); 00304 return equal128 (l, r); 00305 } else { 00306 /* BUG: One of the numbers has a reciprocal denom, and the other 00307 does not. I just don't know to handle this case in any 00308 reasonably overflow-proof yet simple way. So, this funtion 00309 will simply get it wrong whenever the three multiplies 00310 overflow 64-bits. -CAS */ 00311 if (a.denom < 0) { 00312 return ((a.num * -a.denom * b.denom) == b.num); 00313 } else { 00314 return (a.num == (b.num * a.denom * -b.denom)); 00315 } 00316 } 00317 00318 return ((a.num * b.denom) == (a.denom * b.num)); 00319 }
|
|
Create a gnc_numeric object that signals the error condition noted by error_code, rather than a number. Definition at line 1112 of file gnc-numeric.c. 01113 { 01114 return gnc_numeric_create(error_code, 0LL); 01115 }
|
|
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 456 of file gnc-numeric.c. 00458 { 00459 gnc_numeric product, result; 00460 qofint128 bignume, bigdeno; 00461 00462 if(gnc_numeric_check(a) || gnc_numeric_check(b)) { 00463 return gnc_numeric_error(GNC_ERROR_ARG); 00464 } 00465 00466 if((denom == GNC_DENOM_AUTO) && 00467 (how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_FIXED) { 00468 if(a.denom == b.denom) { 00469 denom = a.denom; 00470 } 00471 else if(b.num == 0) { 00472 denom = a.denom; 00473 } 00474 else if(a.num == 0) { 00475 denom = b.denom; 00476 } 00477 else { 00478 return gnc_numeric_error(GNC_ERROR_DENOM_DIFF); 00479 } 00480 } 00481 00482 if((denom == GNC_DENOM_AUTO) && 00483 ((how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_LCD)) 00484 { 00485 denom = gnc_numeric_lcd(a, b); 00486 how = how & GNC_NUMERIC_RND_MASK; 00487 } 00488 00489 if(a.denom < 0) { 00490 a.num *= -a.denom; /* BUG: overflow not handled. */ 00491 a.denom = 1; 00492 } 00493 00494 if(b.denom < 0) { 00495 b.num *= -b.denom; /* BUG: overflow not handled. */ 00496 b.denom = 1; 00497 } 00498 00499 bignume = mult128 (a.num, b.num); 00500 bigdeno = mult128 (a.denom, b.denom); 00501 product.num = a.num*b.num; 00502 product.denom = a.denom*b.denom; 00503 00504 /* If it looks to be overflowing, try to reduce the fraction ... */ 00505 if (bignume.isbig || bigdeno.isbig) 00506 { 00507 gint64 tmp; 00508 a = gnc_numeric_reduce (a); 00509 b = gnc_numeric_reduce (b); 00510 tmp = a.num; 00511 a.num = b.num; 00512 b.num = tmp; 00513 a = gnc_numeric_reduce (a); 00514 b = gnc_numeric_reduce (b); 00515 00516 bignume = mult128 (a.num, b.num); 00517 bigdeno = mult128 (a.denom, b.denom); 00518 product.num = a.num*b.num; 00519 product.denom = a.denom*b.denom; 00520 } 00521 00522 /* If it its still overflowing, and rounding is allowed then round */ 00523 if (bignume.isbig || bigdeno.isbig) 00524 { 00525 /* If rounding allowed, then shift until there's no 00526 * more overflow. The conversion at the end will fix 00527 * things up for the final value. Else overflow. */ 00528 if ((how & GNC_NUMERIC_RND_MASK) == GNC_HOW_RND_NEVER) 00529 { 00530 if (bigdeno.isbig) 00531 { 00532 return gnc_numeric_error (GNC_ERROR_OVERFLOW); 00533 } 00534 product = reduce128 (bignume, product.denom); 00535 if (gnc_numeric_check (product)) 00536 { 00537 return gnc_numeric_error (GNC_ERROR_OVERFLOW); 00538 } 00539 } 00540 else 00541 { 00542 while (bignume.isbig || bigdeno.isbig) 00543 { 00544 bignume = shift128 (bignume); 00545 bigdeno = shift128 (bigdeno); 00546 } 00547 product.num = bignume.lo; 00548 if (bignume.isneg) product.num = -product.num; 00549 00550 product.denom = bigdeno.lo; 00551 if (0 == product.denom) 00552 { 00553 return gnc_numeric_error (GNC_ERROR_OVERFLOW); 00554 } 00555 } 00556 } 00557 00558 #if 0 /* currently, product denom won't ever be zero */ 00559 if(product.denom < 0) { 00560 product.num = -product.num; 00561 product.denom = -product.denom; 00562 } 00563 #endif 00564 00565 result = gnc_numeric_convert(product, denom, how); 00566 return result; 00567 }
|
|
The same as gnc_numeric_mul, but uses error for accumulating conversion roundoff error. Definition at line 1166 of file gnc-numeric.c. 01169 { 01170 gnc_numeric prod = gnc_numeric_mul(a, b, denom, how); 01171 gnc_numeric exact = gnc_numeric_mul(a, b, GNC_DENOM_AUTO, 01172 GNC_HOW_DENOM_REDUCE); 01173 gnc_numeric err = gnc_numeric_sub(prod, exact, GNC_DENOM_AUTO, 01174 GNC_HOW_DENOM_REDUCE); 01175 if(error) { 01176 *error = err; 01177 } 01178 return prod; 01179 }
|
|
Negate the argument Definition at line 708 of file gnc-numeric.c. 00708 { 00709 if(gnc_numeric_check(a)) { 00710 return gnc_numeric_error(GNC_ERROR_ARG); 00711 } 00712 return gnc_numeric_create(- a.num, a.denom); 00713 }
|
|
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 276 of file gnc-numeric.h. 00276 { 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 991 of file gnc-numeric.c. 00992 { 00993 gint64 t; 00994 gint64 num = (in.num < 0) ? (- in.num) : in.num ; 00995 gint64 denom = in.denom; 00996 gnc_numeric out; 00997 00998 if(gnc_numeric_check(in)) 00999 { 01000 return gnc_numeric_error(GNC_ERROR_ARG); 01001 } 01002 01003 /* The strategy is to use Euclid's algorithm */ 01004 while (denom > 0) { 01005 t = num % denom; 01006 num = denom; 01007 denom = t; 01008 } 01009 /* num now holds the GCD (Greatest Common Divisor) */ 01010 01011 /* All calculations are done on positive num, since it's not 01012 * well defined what % does for negative values */ 01013 out.num = in.num / num; 01014 out.denom = in.denom / num; 01015 return out; 01016 }
|
|
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 329 of file gnc-numeric.c. 00330 { 00331 gnc_numeric aconv, bconv; 00332 00333 aconv = gnc_numeric_convert(a, denom, how); 00334 bconv = gnc_numeric_convert(b, denom, how); 00335 00336 return(gnc_numeric_equal(aconv, bconv)); 00337 }
|
|
Return a-b. Definition at line 437 of file gnc-numeric.c. 00439 { 00440 gnc_numeric nb; 00441 if(gnc_numeric_check(a) || gnc_numeric_check(b)) 00442 { 00443 return gnc_numeric_error(GNC_ERROR_ARG); 00444 } 00445 00446 nb = b; 00447 nb.num = -nb.num; 00448 return gnc_numeric_add (a, nb, denom, how); 00449 }
|
|
Shortcut for most common case: gnc_numeric_sub(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_FIXED | GNC_HOW_RND_NEVER); Definition at line 390 of file gnc-numeric.h. 00390 { 00391 return gnc_numeric_sub(a, b, GNC_DENOM_AUTO, 00392 GNC_HOW_DENOM_FIXED | GNC_HOW_RND_NEVER); 00393 }
|
|
The same as gnc_numeric_sub, but uses error for accumulating conversion roundoff error. Definition at line 1145 of file gnc-numeric.c. 01148 { 01149 gnc_numeric diff = gnc_numeric_sub(a, b, denom, how); 01150 gnc_numeric exact = gnc_numeric_sub(a, b, GNC_DENOM_AUTO, 01151 GNC_HOW_DENOM_REDUCE); 01152 gnc_numeric err = gnc_numeric_sub(diff, exact, GNC_DENOM_AUTO, 01153 GNC_HOW_DENOM_REDUCE); 01154 if(error) { 01155 *error = err; 01156 } 01157 return diff; 01158 }
|
|
Convert numeric to floating-point value. Definition at line 1095 of file gnc-numeric.c. 01096 { 01097 if(in.denom > 0) 01098 { 01099 return (double)in.num/(double)in.denom; 01100 } 01101 else 01102 { 01103 return (double)(in.num * -in.denom); 01104 } 01105 }
|
|
Convert to string. The returned buffer is to be g_free'd by the caller (it was allocated through g_strdup) Definition at line 1207 of file gnc-numeric.c. 01208 { 01209 gchar *result; 01210 gint64 tmpnum = n.num; 01211 gint64 tmpdenom = n.denom; 01212 01213 result = g_strdup_printf("%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, tmpnum, tmpdenom); 01214 01215 return result; 01216 }
|
|
create a zero-value gnc_numeric Definition at line 250 of file gnc-numeric.h. 00250 { 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 1235 of file gnc-numeric.c. 01236 { 01237 size_t num_read; 01238 gint64 tmpnum; 01239 gint64 tmpdenom; 01240 01241 if(!str) return FALSE; 01242 01243 #ifdef GNC_DEPRECATED 01244 /* must use "<" here because %n's effects aren't well defined */ 01245 if(sscanf(str, " " GNC_SCANF_LLD "/" GNC_SCANF_LLD "%n", 01246 &tmpnum, &tmpdenom, &num_read) < 2) { 01247 return FALSE; 01248 } 01249 #else 01250 tmpnum = strtoll (str, NULL, 0); 01251 str = strchr (str, '/'); 01252 if (!str) return FALSE; 01253 str ++; 01254 tmpdenom = strtoll (str, NULL, 0); 01255 num_read = strspn (str, "0123456789"); 01256 #endif 01257 n->num = tmpnum; 01258 n->denom = tmpdenom; 01259 return TRUE; 01260 }
|