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.
Files | |
file | gnc-numeric.h |
An exact-rational-number library for QOF. (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 | |
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 | |
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) |
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 232 of file gnc-numeric.h. |
|
Use the value 1/n as the denominator of the output value. Definition at line 235 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 204 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. |
|
An rational-number type. This is a rational number, defined by numerator and denominator. Definition at line 62 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. 00131 { 00133 GNC_HOW_RND_FLOOR = 0x01, 00134 00136 GNC_HOW_RND_CEIL = 0x02, 00137 00139 GNC_HOW_RND_TRUNC = 0x03, 00140 00142 GNC_HOW_RND_PROMOTE = 0x04, 00143 00147 GNC_HOW_RND_ROUND_HALF_DOWN = 0x05, 00148 00152 GNC_HOW_RND_ROUND_HALF_UP = 0x06, 00153 00159 GNC_HOW_RND_ROUND = 0x07, 00160 00164 GNC_HOW_RND_NEVER = 0x08 00165 };
|
|
How to compute a denominator, or'ed into the "how" field.
Definition at line 168 of file gnc-numeric.h. 00169 { 00175 GNC_HOW_DENOM_EXACT = 0x10, 00176 00182 GNC_HOW_DENOM_REDUCE = 0x20, 00183 00187 GNC_HOW_DENOM_LCD = 0x30, 00188 00193 GNC_HOW_DENOM_FIXED = 0x40, 00194 00198 GNC_HOW_DENOM_SIGFIG = 0x50 00199 };
|
|
Error codes
Definition at line 208 of file gnc-numeric.h. 00209 { 00210 GNC_ERROR_OK = 0, 00211 GNC_ERROR_ARG = -1, 00212 GNC_ERROR_OVERFLOW = -2, 00215 GNC_ERROR_DENOM_DIFF = -3, 00216 00219 GNC_ERROR_REMAINDER = -4 00220 } 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 1065 of file gnc-numeric.c. 01066 { 01067 gnc_numeric out; 01068 gint64 int_part = 0; 01069 double frac_part; 01070 gint64 frac_int = 0; 01071 double logval; 01072 double sigfigs; 01073 01074 if ((denom == GNC_DENOM_AUTO) && (how & GNC_HOW_DENOM_SIGFIG)) 01075 { 01076 if (fabs (in) < 10e-20) 01077 { 01078 logval = 0; 01079 } 01080 else 01081 { 01082 logval = log10 (fabs (in)); 01083 logval = ((logval > 0.0) ? 01084 (floor (logval) + 1.0) : (ceil (logval))); 01085 } 01086 sigfigs = GNC_HOW_GET_SIGFIGS (how); 01087 if (sigfigs - logval >= 0) 01088 { 01089 denom = (gint64) (pow (10, sigfigs - logval)); 01090 } 01091 else 01092 { 01093 denom = -((gint64) (pow (10, logval - sigfigs))); 01094 } 01095 01096 how = how & ~GNC_HOW_DENOM_SIGFIG & ~GNC_NUMERIC_SIGFIGS_MASK; 01097 } 01098 01099 int_part = (gint64) (floor (fabs (in))); 01100 frac_part = in - (double) int_part; 01101 01102 int_part = int_part * denom; 01103 frac_part = frac_part * (double) denom; 01104 01105 switch (how & GNC_NUMERIC_RND_MASK) 01106 { 01107 case GNC_HOW_RND_FLOOR: 01108 frac_int = (gint64) floor (frac_part); 01109 break; 01110 01111 case GNC_HOW_RND_CEIL: 01112 frac_int = (gint64) ceil (frac_part); 01113 break; 01114 01115 case GNC_HOW_RND_TRUNC: 01116 frac_int = (gint64) frac_part; 01117 break; 01118 01119 case GNC_HOW_RND_ROUND: 01120 case GNC_HOW_RND_ROUND_HALF_UP: 01121 frac_int = (gint64) rint (frac_part); 01122 break; 01123 01124 case GNC_HOW_RND_NEVER: 01125 frac_int = (gint64) floor (frac_part); 01126 if (frac_part != (double) frac_int) 01127 { 01128 /* signal an error */ 01129 } 01130 break; 01131 } 01132 01133 out.num = int_part + frac_int; 01134 out.denom = denom; 01135 return out; 01136 }
|
|
Convert to string. Uses a static, non-thread-safe buffer. For internal use only. Definition at line 1269 of file gnc-numeric.c. 01270 { 01271 static char buff[1000]; 01272 static char *p = buff; 01273 gint64 tmpnum = n.num; 01274 gint64 tmpdenom = n.denom; 01275 01276 p += 100; 01277 if (p - buff >= 1000) 01278 p = buff; 01279 01280 sprintf (p, "%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, tmpnum, 01281 tmpdenom); 01282 01283 return p; 01284 }
|
|
Return the absolute value of the argument Definition at line 749 of file gnc-numeric.c. 00750 { 00751 if (gnc_numeric_check (a)) 00752 { 00753 return gnc_numeric_error (GNC_ERROR_ARG); 00754 } 00755 return gnc_numeric_create (ABS (a.num), a.denom); 00756 }
|
|
Return a+b. Definition at line 358 of file gnc-numeric.c. 00359 { 00360 gnc_numeric sum; 00361 00362 if (gnc_numeric_check (a) || gnc_numeric_check (b)) 00363 { 00364 return gnc_numeric_error (GNC_ERROR_ARG); 00365 } 00366 00367 if ((denom == GNC_DENOM_AUTO) && 00368 (how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_FIXED) 00369 { 00370 if (a.denom == b.denom) 00371 { 00372 denom = a.denom; 00373 } 00374 else if (b.num == 0) 00375 { 00376 denom = a.denom; 00377 b.denom = a.denom; 00378 } 00379 else if (a.num == 0) 00380 { 00381 denom = b.denom; 00382 a.denom = b.denom; 00383 } 00384 else 00385 { 00386 return gnc_numeric_error (GNC_ERROR_DENOM_DIFF); 00387 } 00388 } 00389 00390 if (a.denom < 0) 00391 { 00392 a.num *= -a.denom; /* BUG: overflow not handled. */ 00393 a.denom = 1; 00394 } 00395 00396 if (b.denom < 0) 00397 { 00398 b.num *= -b.denom; /* BUG: overflow not handled. */ 00399 b.denom = 1; 00400 } 00401 00402 /* Get an exact answer.. same denominator is the common case. */ 00403 if (a.denom == b.denom) 00404 { 00405 sum.num = a.num + b.num; /* BUG: overflow not handled. */ 00406 sum.denom = a.denom; 00407 } 00408 else 00409 { 00410 /* We want to do this: 00411 * sum.num = a.num*b.denom + b.num*a.denom; 00412 * sum.denom = a.denom*b.denom; 00413 * but the multiply could overflow. 00414 * Computing the LCD minimizes likelihood of overflow 00415 */ 00416 gint64 lcd; 00417 qofint128 ca, cb, cab; 00418 lcd = gnc_numeric_lcd (a, b); 00419 if (GNC_ERROR_ARG == lcd) 00420 { 00421 return gnc_numeric_error (GNC_ERROR_OVERFLOW); 00422 } 00423 ca = mult128 (a.num, lcd / a.denom); 00424 if (ca.isbig) 00425 return gnc_numeric_error (GNC_ERROR_OVERFLOW); 00426 00427 cb = mult128 (b.num, lcd / b.denom); 00428 if (cb.isbig) 00429 return gnc_numeric_error (GNC_ERROR_OVERFLOW); 00430 00431 cab = add128 (ca, cb); 00432 if (cab.isbig) 00433 return gnc_numeric_error (GNC_ERROR_OVERFLOW); 00434 00435 sum.num = cab.lo; 00436 if (cab.isneg) 00437 sum.num = -sum.num; 00438 sum.denom = lcd; 00439 } 00440 00441 if ((denom == GNC_DENOM_AUTO) && 00442 ((how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_LCD)) 00443 { 00444 denom = gnc_numeric_lcd (a, b); 00445 how = how & GNC_NUMERIC_RND_MASK; 00446 } 00447 00448 return gnc_numeric_convert (sum, denom, how); 00449 }
|
|
The same as gnc_numeric_add, but uses 'error' for accumulating conversion roundoff error. Definition at line 1171 of file gnc-numeric.c. 01173 { 01174 01175 gnc_numeric sum = gnc_numeric_add (a, b, denom, how); 01176 gnc_numeric exact = gnc_numeric_add (a, b, GNC_DENOM_AUTO, 01177 GNC_HOW_DENOM_REDUCE); 01178 gnc_numeric err = gnc_numeric_sub (sum, exact, GNC_DENOM_AUTO, 01179 GNC_HOW_DENOM_REDUCE); 01180 01181 if (error) 01182 { 01183 *error = err; 01184 } 01185 return sum; 01186 }
|
|
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 55 of file gnc-numeric.c. 00056 { 00057 if (in.denom != 0) 00058 { 00059 return GNC_ERROR_OK; 00060 } 00061 else if (in.num) 00062 { 00063 if ((0 < in.num) || (-4 > in.num)) 00064 { 00065 in.num = (gint64) GNC_ERROR_OVERFLOW; 00066 } 00067 return (GNCNumericErrorCode) in.num; 00068 } 00069 else 00070 { 00071 return GNC_ERROR_ARG; 00072 } 00073 }
|
|
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) 00234 return 0; 00235 if (a.num > b.num) 00236 return 1; 00237 return -1; 00238 } 00239 00240 if ((a.denom > 0) && (b.denom > 0)) 00241 { 00242 /* Avoid overflows using 128-bit intermediate math */ 00243 l = mult128 (a.num, b.denom); 00244 r = mult128 (b.num, a.denom); 00245 return cmp128 (l, r); 00246 } 00247 00248 if (a.denom < 0) 00249 a.denom *= -1; 00250 if (b.denom < 0) 00251 b.denom *= -1; 00252 00253 /* BUG: Possible overflow here.. Also, doesn't properly deal with 00254 * reciprocal denominators. 00255 */ 00256 aa = a.num * a.denom; 00257 bb = b.num * b.denom; 00258 00259 if (aa == bb) 00260 return 0; 00261 if (aa > bb) 00262 return 1; 00263 return -1; 00264 }
|
|
Change the denominator of a gnc_numeric value to the specified denominator under standard arguments 'denom' and 'how'. Definition at line 763 of file gnc-numeric.c. 00764 { 00765 gnc_numeric out; 00766 gnc_numeric temp; 00767 gint64 temp_bc; 00768 gint64 temp_a; 00769 gint64 remainder; 00770 gint64 sign; 00771 gint denom_neg = 0; 00772 double ratio, logratio; 00773 double sigfigs; 00774 qofint128 nume, newm; 00775 00776 temp.num = 0; 00777 temp.denom = 0; 00778 00779 if (gnc_numeric_check (in)) 00780 { 00781 return gnc_numeric_error (GNC_ERROR_ARG); 00782 } 00783 00784 if (denom == GNC_DENOM_AUTO) 00785 { 00786 switch (how & GNC_NUMERIC_DENOM_MASK) 00787 { 00788 default: 00789 case GNC_HOW_DENOM_LCD: /* LCD is meaningless with AUTO in here */ 00790 case GNC_HOW_DENOM_EXACT: 00791 return in; 00792 break; 00793 00794 case GNC_HOW_DENOM_REDUCE: 00795 /* reduce the input to a relatively-prime fraction */ 00796 return gnc_numeric_reduce (in); 00797 break; 00798 00799 case GNC_HOW_DENOM_FIXED: 00800 if (in.denom != denom) 00801 { 00802 return gnc_numeric_error (GNC_ERROR_DENOM_DIFF); 00803 } 00804 else 00805 { 00806 return in; 00807 } 00808 break; 00809 00810 case GNC_HOW_DENOM_SIGFIG: 00811 ratio = fabs (gnc_numeric_to_double (in)); 00812 if (ratio < 10e-20) 00813 { 00814 logratio = 0; 00815 } 00816 else 00817 { 00818 logratio = log10 (ratio); 00819 logratio = ((logratio > 0.0) ? 00820 (floor (logratio) + 1.0) : (ceil (logratio))); 00821 } 00822 sigfigs = GNC_HOW_GET_SIGFIGS (how); 00823 00824 if (sigfigs - logratio >= 0) 00825 { 00826 denom = (gint64) (pow (10, sigfigs - logratio)); 00827 } 00828 else 00829 { 00830 denom = -((gint64) (pow (10, logratio - sigfigs))); 00831 } 00832 00833 how = how & ~GNC_HOW_DENOM_SIGFIG & ~GNC_NUMERIC_SIGFIGS_MASK; 00834 break; 00835 00836 } 00837 } 00838 00839 /* Make sure we need to do the work */ 00840 if (in.denom == denom) 00841 { 00842 return in; 00843 } 00844 if (in.num == 0) 00845 { 00846 out.num = 0; 00847 out.denom = denom; 00848 return out; 00849 } 00850 00851 /* If the denominator of the input value is negative, get rid of that. */ 00852 if (in.denom < 0) 00853 { 00854 in.num = in.num * (-in.denom); /* BUG: overflow not handled. */ 00855 in.denom = 1; 00856 } 00857 00858 sign = (in.num < 0) ? -1 : 1; 00859 00860 /* If the denominator is less than zero, we are to interpret it as 00861 * the reciprocal of its magnitude. */ 00862 if (denom < 0) 00863 { 00864 00865 /* XXX FIXME: use 128-bit math here ... */ 00866 denom = -denom; 00867 denom_neg = 1; 00868 temp_a = (in.num < 0) ? -in.num : in.num; 00869 temp_bc = in.denom * denom; /* BUG: overflow not handled. */ 00870 remainder = temp_a % temp_bc; 00871 out.num = temp_a / temp_bc; 00872 out.denom = -denom; 00873 } 00874 else 00875 { 00876 /* Do all the modulo and int division on positive values to make 00877 * things a little clearer. Reduce the fraction denom/in.denom to 00878 * help with range errors */ 00879 temp.num = denom; 00880 temp.denom = in.denom; 00881 temp = gnc_numeric_reduce (temp); 00882 00883 /* Symbolically, do the following: 00884 * out.num = in.num * temp.num; 00885 * remainder = out.num % temp.denom; 00886 * out.num = out.num / temp.denom; 00887 * out.denom = denom; 00888 */ 00889 nume = mult128 (in.num, temp.num); 00890 newm = div128 (nume, temp.denom); 00891 remainder = rem128 (nume, temp.denom); 00892 00893 if (newm.isbig) 00894 { 00895 return gnc_numeric_error (GNC_ERROR_OVERFLOW); 00896 } 00897 00898 out.num = newm.lo; 00899 out.denom = denom; 00900 } 00901 00902 if (remainder) 00903 { 00904 switch (how & GNC_NUMERIC_RND_MASK) 00905 { 00906 case GNC_HOW_RND_FLOOR: 00907 if (sign < 0) 00908 { 00909 out.num = out.num + 1; 00910 } 00911 break; 00912 00913 case GNC_HOW_RND_CEIL: 00914 if (sign > 0) 00915 { 00916 out.num = out.num + 1; 00917 } 00918 break; 00919 00920 case GNC_HOW_RND_TRUNC: 00921 break; 00922 00923 case GNC_HOW_RND_PROMOTE: 00924 out.num = out.num + 1; 00925 break; 00926 00927 case GNC_HOW_RND_ROUND_HALF_DOWN: 00928 if (denom_neg) 00929 { 00930 if ((2 * remainder) > in.denom * denom) 00931 { 00932 out.num = out.num + 1; 00933 } 00934 } 00935 else if ((2 * remainder) > temp.denom) 00936 { 00937 out.num = out.num + 1; 00938 } 00939 /* check that 2*remainder didn't over-flow */ 00940 else if (((2 * remainder) < remainder) && 00941 (remainder > (temp.denom / 2))) 00942 { 00943 out.num = out.num + 1; 00944 } 00945 break; 00946 00947 case GNC_HOW_RND_ROUND_HALF_UP: 00948 if (denom_neg) 00949 { 00950 if ((2 * remainder) >= in.denom * denom) 00951 { 00952 out.num = out.num + 1; 00953 } 00954 } 00955 else if ((2 * remainder) >= temp.denom) 00956 { 00957 out.num = out.num + 1; 00958 } 00959 /* check that 2*remainder didn't over-flow */ 00960 else if (((2 * remainder) < remainder) && 00961 (remainder >= (temp.denom / 2))) 00962 { 00963 out.num = out.num + 1; 00964 } 00965 break; 00966 00967 case GNC_HOW_RND_ROUND: 00968 if (denom_neg) 00969 { 00970 if ((2 * remainder) > in.denom * denom) 00971 { 00972 out.num = out.num + 1; 00973 } 00974 else if ((2 * remainder) == in.denom * denom) 00975 { 00976 if (out.num % 2) 00977 { 00978 out.num = out.num + 1; 00979 } 00980 } 00981 } 00982 else 00983 { 00984 if ((2 * remainder) > temp.denom) 00985 { 00986 out.num = out.num + 1; 00987 } 00988 /* check that 2*remainder didn't over-flow */ 00989 else if (((2 * remainder) < remainder) && 00990 (remainder > (temp.denom / 2))) 00991 { 00992 out.num = out.num + 1; 00993 } 00994 else if ((2 * remainder) == temp.denom) 00995 { 00996 if (out.num % 2) 00997 { 00998 out.num = out.num + 1; 00999 } 01000 } 01001 /* check that 2*remainder didn't over-flow */ 01002 else if (((2 * remainder) < remainder) && 01003 (remainder == (temp.denom / 2))) 01004 { 01005 if (out.num % 2) 01006 { 01007 out.num = out.num + 1; 01008 } 01009 } 01010 } 01011 break; 01012 01013 case GNC_HOW_RND_NEVER: 01014 return gnc_numeric_error (GNC_ERROR_REMAINDER); 01015 break; 01016 } 01017 } 01018 01019 out.num = (sign > 0) ? out.num : (-out.num); 01020 01021 return out; 01022 }
|
|
Same as gnc_numeric_convert, but return a remainder value for accumulating conversion error. |
|
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 602 of file gnc-numeric.c. 00603 { 00604 gnc_numeric quotient; 00605 qofint128 nume, deno; 00606 00607 if (gnc_numeric_check (a) || gnc_numeric_check (b)) 00608 { 00609 return gnc_numeric_error (GNC_ERROR_ARG); 00610 } 00611 00612 if ((denom == GNC_DENOM_AUTO) && 00613 (how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_FIXED) 00614 { 00615 if (a.denom == b.denom) 00616 { 00617 denom = a.denom; 00618 } 00619 else if (a.denom == 0) 00620 { 00621 denom = b.denom; 00622 } 00623 else 00624 { 00625 return gnc_numeric_error (GNC_ERROR_DENOM_DIFF); 00626 } 00627 } 00628 00629 00630 if (a.denom < 0) 00631 { 00632 a.num *= -a.denom; /* BUG: overflow not handled. */ 00633 a.denom = 1; 00634 } 00635 00636 if (b.denom < 0) 00637 { 00638 b.num *= -b.denom; /* BUG: overflow not handled. */ 00639 b.denom = 1; 00640 } 00641 00642 if (a.denom == b.denom) 00643 { 00644 quotient.num = a.num; 00645 quotient.denom = b.num; 00646 } 00647 else 00648 { 00649 gint64 sgn = 1; 00650 if (0 > a.num) 00651 { 00652 sgn = -sgn; 00653 a.num = -a.num; 00654 } 00655 if (0 > b.num) 00656 { 00657 sgn = -sgn; 00658 b.num = -b.num; 00659 } 00660 nume = mult128 (a.num, b.denom); 00661 deno = mult128 (b.num, a.denom); 00662 00663 /* Try to avoid overflow by removing common factors */ 00664 if (nume.isbig && deno.isbig) 00665 { 00666 gnc_numeric ra = gnc_numeric_reduce (a); 00667 gnc_numeric rb = gnc_numeric_reduce (b); 00668 00669 gint64 gcf_nume = gcf64 (ra.num, rb.num); 00670 gint64 gcf_deno = gcf64 (rb.denom, ra.denom); 00671 nume = mult128 (ra.num / gcf_nume, rb.denom / gcf_deno); 00672 deno = mult128 (rb.num / gcf_nume, ra.denom / gcf_deno); 00673 } 00674 00675 if ((0 == nume.isbig) && (0 == deno.isbig)) 00676 { 00677 quotient.num = sgn * nume.lo; 00678 quotient.denom = deno.lo; 00679 goto dive_done; 00680 } 00681 else if (0 == deno.isbig) 00682 { 00683 quotient = reduce128 (nume, deno.lo); 00684 if (0 == gnc_numeric_check (quotient)) 00685 { 00686 quotient.num *= sgn; 00687 goto dive_done; 00688 } 00689 } 00690 00691 /* If rounding allowed, then shift until there's no 00692 * more overflow. The conversion at the end will fix 00693 * things up for the final value. */ 00694 if ((how & GNC_NUMERIC_RND_MASK) == GNC_HOW_RND_NEVER) 00695 { 00696 return gnc_numeric_error (GNC_ERROR_OVERFLOW); 00697 } 00698 while (nume.isbig || deno.isbig) 00699 { 00700 nume = shift128 (nume); 00701 deno = shift128 (deno); 00702 } 00703 quotient.num = sgn * nume.lo; 00704 quotient.denom = deno.lo; 00705 if (0 == quotient.denom) 00706 { 00707 return gnc_numeric_error (GNC_ERROR_OVERFLOW); 00708 } 00709 } 00710 00711 if (quotient.denom < 0) 00712 { 00713 quotient.num = -quotient.num; 00714 quotient.denom = -quotient.denom; 00715 } 00716 00717 dive_done: 00718 if ((denom == GNC_DENOM_AUTO) && 00719 ((how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_LCD)) 00720 { 00721 denom = gnc_numeric_lcd (a, b); 00722 how = how & GNC_NUMERIC_RND_MASK; 00723 } 00724 00725 return gnc_numeric_convert (quotient, denom, how); 00726 }
|
|
The same as gnc_numeric_div, but uses error for accumulating conversion roundoff error. Definition at line 1235 of file gnc-numeric.c. 01237 { 01238 gnc_numeric quot = gnc_numeric_div (a, b, denom, how); 01239 gnc_numeric exact = gnc_numeric_div (a, b, GNC_DENOM_AUTO, 01240 GNC_HOW_DENOM_REDUCE); 01241 gnc_numeric err = gnc_numeric_sub (quot, exact, 01242 GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE); 01243 if (error) 01244 { 01245 *error = err; 01246 } 01247 return quot; 01248 }
|
|
Equivalence predicate: Returns TRUE (1) if a and b are exactly the same (have the same numerator and denominator) Definition at line 272 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 283 of file gnc-numeric.c. 00284 { 00285 qofint128 l, r; 00286 if ((a.denom == b.denom) && (a.denom > 0)) 00287 { 00288 return (a.num == b.num); 00289 } 00290 if ((a.denom > 0) && (b.denom > 0)) 00291 { 00292 // return (a.num*b.denom == b.num*a.denom); 00293 l = mult128 (a.num, b.denom); 00294 r = mult128 (b.num, a.denom); 00295 return equal128 (l, r); 00296 00297 #if ALT_WAY_OF_CHECKING_EQUALITY 00298 gnc_numeric ra = gnc_numeric_reduce (a); 00299 gnc_numeric rb = gnc_numeric_reduce (b); 00300 if (ra.denom != rb.denom) 00301 return 0; 00302 if (ra.num != rb.num) 00303 return 0; 00304 return 1; 00305 #endif 00306 } 00307 if ((a.denom < 0) && (b.denom < 0)) 00308 { 00309 l = mult128 (a.num, -a.denom); 00310 r = mult128 (b.num, -b.denom); 00311 return equal128 (l, r); 00312 } 00313 else 00314 { 00315 /* BUG: One of the numbers has a reciprocal denom, and the other 00316 does not. I just don't know to handle this case in any 00317 reasonably overflow-proof yet simple way. So, this funtion 00318 will simply get it wrong whenever the three multiplies 00319 overflow 64-bits. -CAS */ 00320 if (a.denom < 0) 00321 { 00322 return ((a.num * -a.denom * b.denom) == b.num); 00323 } 00324 else 00325 { 00326 return (a.num == (b.num * a.denom * -b.denom)); 00327 } 00328 } 00329 00330 return ((a.num * b.denom) == (a.denom * b.num)); 00331 }
|
|
Create a gnc_numeric object that signals the error condition noted by error_code, rather than a number. Definition at line 1160 of file gnc-numeric.c.
|
|
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 474 of file gnc-numeric.c. 00475 { 00476 gnc_numeric product, result; 00477 qofint128 bignume, bigdeno; 00478 00479 if (gnc_numeric_check (a) || gnc_numeric_check (b)) 00480 { 00481 return gnc_numeric_error (GNC_ERROR_ARG); 00482 } 00483 00484 if ((denom == GNC_DENOM_AUTO) && 00485 (how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_FIXED) 00486 { 00487 if (a.denom == b.denom) 00488 { 00489 denom = a.denom; 00490 } 00491 else if (b.num == 0) 00492 { 00493 denom = a.denom; 00494 } 00495 else if (a.num == 0) 00496 { 00497 denom = b.denom; 00498 } 00499 else 00500 { 00501 return gnc_numeric_error (GNC_ERROR_DENOM_DIFF); 00502 } 00503 } 00504 00505 if ((denom == GNC_DENOM_AUTO) && 00506 ((how & GNC_NUMERIC_DENOM_MASK) == GNC_HOW_DENOM_LCD)) 00507 { 00508 denom = gnc_numeric_lcd (a, b); 00509 how = how & GNC_NUMERIC_RND_MASK; 00510 } 00511 00512 if (a.denom < 0) 00513 { 00514 a.num *= -a.denom; /* BUG: overflow not handled. */ 00515 a.denom = 1; 00516 } 00517 00518 if (b.denom < 0) 00519 { 00520 b.num *= -b.denom; /* BUG: overflow not handled. */ 00521 b.denom = 1; 00522 } 00523 00524 bignume = mult128 (a.num, b.num); 00525 bigdeno = mult128 (a.denom, b.denom); 00526 product.num = a.num * b.num; 00527 product.denom = a.denom * b.denom; 00528 00529 /* If it looks to be overflowing, try to reduce the fraction ... */ 00530 if (bignume.isbig || bigdeno.isbig) 00531 { 00532 gint64 tmp; 00533 a = gnc_numeric_reduce (a); 00534 b = gnc_numeric_reduce (b); 00535 tmp = a.num; 00536 a.num = b.num; 00537 b.num = tmp; 00538 a = gnc_numeric_reduce (a); 00539 b = gnc_numeric_reduce (b); 00540 00541 bignume = mult128 (a.num, b.num); 00542 bigdeno = mult128 (a.denom, b.denom); 00543 product.num = a.num * b.num; 00544 product.denom = a.denom * b.denom; 00545 } 00546 00547 /* If it its still overflowing, and rounding is allowed then round */ 00548 if (bignume.isbig || bigdeno.isbig) 00549 { 00550 /* If rounding allowed, then shift until there's no 00551 * more overflow. The conversion at the end will fix 00552 * things up for the final value. Else overflow. */ 00553 if ((how & GNC_NUMERIC_RND_MASK) == GNC_HOW_RND_NEVER) 00554 { 00555 if (bigdeno.isbig) 00556 { 00557 return gnc_numeric_error (GNC_ERROR_OVERFLOW); 00558 } 00559 product = reduce128 (bignume, product.denom); 00560 if (gnc_numeric_check (product)) 00561 { 00562 return gnc_numeric_error (GNC_ERROR_OVERFLOW); 00563 } 00564 } 00565 else 00566 { 00567 while (bignume.isbig || bigdeno.isbig) 00568 { 00569 bignume = shift128 (bignume); 00570 bigdeno = shift128 (bigdeno); 00571 } 00572 product.num = bignume.lo; 00573 if (bignume.isneg) 00574 product.num = -product.num; 00575 00576 product.denom = bigdeno.lo; 00577 if (0 == product.denom) 00578 { 00579 return gnc_numeric_error (GNC_ERROR_OVERFLOW); 00580 } 00581 } 00582 } 00583 00584 #if 0 /* currently, product denom won't ever be zero */ 00585 if (product.denom < 0) 00586 { 00587 product.num = -product.num; 00588 product.denom = -product.denom; 00589 } 00590 #endif 00591 00592 result = gnc_numeric_convert (product, denom, how); 00593 return result; 00594 }
|
|
The same as gnc_numeric_mul, but uses error for accumulating conversion roundoff error. Definition at line 1214 of file gnc-numeric.c. 01216 { 01217 gnc_numeric prod = gnc_numeric_mul (a, b, denom, how); 01218 gnc_numeric exact = gnc_numeric_mul (a, b, GNC_DENOM_AUTO, 01219 GNC_HOW_DENOM_REDUCE); 01220 gnc_numeric err = gnc_numeric_sub (prod, exact, GNC_DENOM_AUTO, 01221 GNC_HOW_DENOM_REDUCE); 01222 if (error) 01223 { 01224 *error = err; 01225 } 01226 return prod; 01227 }
|
|
Negate the argument Definition at line 734 of file gnc-numeric.c. 00735 { 00736 if (gnc_numeric_check (a)) 00737 { 00738 return gnc_numeric_error (GNC_ERROR_ARG); 00739 } 00740 return gnc_numeric_create (-a.num, a.denom); 00741 }
|
|
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 }
|
|
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 1032 of file gnc-numeric.c. 01033 { 01034 gint64 t; 01035 gint64 num = (in.num < 0) ? (-in.num) : in.num; 01036 gint64 denom = in.denom; 01037 gnc_numeric out; 01038 01039 if (gnc_numeric_check (in)) 01040 { 01041 return gnc_numeric_error (GNC_ERROR_ARG); 01042 } 01043 01044 /* The strategy is to use Euclid's algorithm */ 01045 while (denom > 0) 01046 { 01047 t = num % denom; 01048 num = denom; 01049 denom = t; 01050 } 01051 /* num now holds the GCD (Greatest Common Divisor) */ 01052 01053 /* All calculations are done on positive num, since it's not 01054 * well defined what % does for negative values */ 01055 out.num = in.num / num; 01056 out.denom = in.denom / num; 01057 return out; 01058 }
|
|
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 341 of file gnc-numeric.c. 00342 { 00343 gnc_numeric aconv, bconv; 00344 00345 aconv = gnc_numeric_convert (a, denom, how); 00346 bconv = gnc_numeric_convert (b, denom, how); 00347 00348 return (gnc_numeric_equal (aconv, bconv)); 00349 }
|
|
Return a-b. Definition at line 456 of file gnc-numeric.c. 00457 { 00458 gnc_numeric nb; 00459 if (gnc_numeric_check (a) || gnc_numeric_check (b)) 00460 { 00461 return gnc_numeric_error (GNC_ERROR_ARG); 00462 } 00463 00464 nb = b; 00465 nb.num = -nb.num; 00466 return gnc_numeric_add (a, nb, denom, how); 00467 }
|
|
The same as gnc_numeric_sub, but uses error for accumulating conversion roundoff error. Definition at line 1193 of file gnc-numeric.c. 01195 { 01196 gnc_numeric diff = gnc_numeric_sub (a, b, denom, how); 01197 gnc_numeric exact = gnc_numeric_sub (a, b, GNC_DENOM_AUTO, 01198 GNC_HOW_DENOM_REDUCE); 01199 gnc_numeric err = gnc_numeric_sub (diff, exact, GNC_DENOM_AUTO, 01200 GNC_HOW_DENOM_REDUCE); 01201 if (error) 01202 { 01203 *error = err; 01204 } 01205 return diff; 01206 }
|
|
Convert numeric to floating-point value. Definition at line 1143 of file gnc-numeric.c. 01144 { 01145 if (in.denom > 0) 01146 { 01147 return (double) in.num / (double) in.denom; 01148 } 01149 else 01150 { 01151 return (double) (in.num * -in.denom); 01152 } 01153 }
|
|
Convert to string. The returned buffer is to be g_free'd by the caller (it was allocated through g_strdup) Definition at line 1255 of file gnc-numeric.c. 01256 { 01257 gchar *result; 01258 gint64 tmpnum = n.num; 01259 gint64 tmpdenom = n.denom; 01260 01261 result = 01262 g_strdup_printf ("%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, tmpnum, 01263 tmpdenom); 01264 01265 return result; 01266 }
|
|
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 1287 of file gnc-numeric.c. 01288 { 01289 size_t num_read; 01290 gint64 tmpnum; 01291 gint64 tmpdenom; 01292 01293 if (!str) 01294 return FALSE; 01295 01296 #ifdef GNC_DEPRECATED 01297 /* must use "<" here because %n's effects aren't well defined */ 01298 if (sscanf (str, " " GNC_SCANF_LLD "/" GNC_SCANF_LLD "%n", 01299 &tmpnum, &tmpdenom, &num_read) < 2) 01300 { 01301 return FALSE; 01302 } 01303 #else 01304 tmpnum = strtoll (str, NULL, 0); 01305 str = strchr (str, '/'); 01306 if (!str) 01307 return FALSE; 01308 str++; 01309 tmpdenom = strtoll (str, NULL, 0); 01310 num_read = strspn (str, "0123456789"); 01311 #endif 01312 n->num = tmpnum; 01313 n->denom = tmpdenom; 01314 return TRUE; 01315 }
|