[Gnucash-changes] -- check for overflow during numeric multiply --
remove dead code (old
Linas Vepstas
linas at cvs.gnucash.org
Sat May 29 21:47:38 EDT 2004
Log Message:
-----------
-- check for overflow during numeric multiply
-- remove dead code (old common-factor finder)
Modified Files:
--------------
gnucash/src/engine:
gnc-numeric.c
Revision Data
-------------
Index: gnc-numeric.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/gnc-numeric.c,v
retrieving revision 1.31
retrieving revision 1.32
diff -Lsrc/engine/gnc-numeric.c -Lsrc/engine/gnc-numeric.c -u -r1.31 -r1.32
--- src/engine/gnc-numeric.c
+++ src/engine/gnc-numeric.c
@@ -49,7 +49,7 @@
} gncint128;
static inline gncint128
-mult (gint64 a, gint64 b)
+mult128 (gint64 a, gint64 b)
{
gncint128 prod;
short aneg=0, bneg=0;
@@ -113,7 +113,7 @@
#ifdef TEST_128_BIT_MULT
void pr (gint64 a, gint64 b)
{
- gncint128 prod = mult (a,b);
+ gncint128 prod = mult128 (a,b);
printf ("%lld * %lld = %lld %llu (0x%llx %llx)\n", a,b, prod.hi, prod.lo, prod.hi, prod.lo);
}
@@ -468,6 +468,7 @@
gint64 denom, gint how)
{
gnc_numeric product, result;
+ gncint128 bigprod;
if(gnc_numeric_check(a) || gnc_numeric_check(b)) {
return gnc_numeric_error(GNC_ERROR_ARG);
@@ -499,8 +500,15 @@
b.denom = 1;
}
+ bigprod = mult128 (a.num, b.num);
product.num = a.num*b.num;
product.denom = a.denom*b.denom;
+
+ if (0 != bigprod.hi)
+ {
+ /* We can try to do better, by reducing the fraction ... */
+ return gnc_numeric_error (GNC_ERROR_OVERFLOW);
+ }
#if 0 /* currently, product denom won't ever be zero */
if(product.denom < 0) {
@@ -880,15 +888,14 @@
/********************************************************************
- * gnc_numeric_reduce
- * reduce a fraction by GCF elimination. This is NOT done as a
+ ** reduce a fraction by GCF elimination. This is NOT done as a
* part of the arithmetic API unless GNC_DENOM_REDUCE is specified
* as the output denominator.
********************************************************************/
-#if 1
gnc_numeric
-gnc_numeric_reduce(gnc_numeric in) {
+gnc_numeric_reduce(gnc_numeric in)
+{
gint64 t;
gint64 num = (in.num < 0) ? (- in.num) : in.num ;
gint64 denom = in.denom;
@@ -898,97 +905,21 @@
return gnc_numeric_error(GNC_ERROR_ARG);
}
- /* the strategy is to use euclid's algorithm */
+ /* The strategy is to use Euclid's algorithm */
while (denom > 0) {
t = num % denom;
num = denom;
denom = t;
}
- /* num = gcd */
+ /* num now holds the GCD (Greatest Common Divisor) */
- /* all calculations are done on positive num, since it's not
+ /* All calculations are done on positive num, since it's not
* well defined what % does for negative values */
out.num = in.num / num;
out.denom = in.denom / num;
return out;
}
-#else
-gnc_numeric
-gnc_numeric_reduce(gnc_numeric in) {
-
- gint64 current_divisor = 2;
- gint64 max_square;
- gint64 num = (in.num < 0) ? (- in.num) : in.num ;
- gint64 denom = in.denom;
- int three_count = 0;
- gnc_numeric out;
-
- if(gnc_numeric_check(in)) {
- return gnc_numeric_error(GNC_ERROR_ARG);
- }
-
- /* the strategy is to eliminate common factors from
- * 2 up to 'max', where max is the smaller of the smaller
- * part of the fraction and the sqrt of the larger part of
- * the fraction. There's also the special case of the
- * smaller of fraction parts being a common factor.
- *
- * we test for 2 and 3 first, and thereafter skip all even numbers
- * and all odd multiples of 3 (that's every third odd number,
- * i.e. 9, 15, 21), thus the three_count stuff. */
-
- /* special case: one side divides evenly by the other */
- if (num == 0) {
- denom = 1;
- }
- else if((num > denom) && (num % denom == 0)) {
- num = num / denom;
- denom = 1;
- }
- else if ((num <= denom) && (denom % num == 0)) {
- denom = denom / num;
- num = 1;
- }
-
- max_square = (num > denom) ? denom : num;
-
- /* normal case: test 2, then 3, 5, 7, 11, etc.
- * (skip multiples of 2 and 3) */
- while(current_divisor * current_divisor <= max_square) {
- if((num % current_divisor == 0) &&
- (denom % current_divisor == 0)) {
- num = num / current_divisor;
- denom = denom / current_divisor;
- }
- else {
- if(current_divisor == 2) {
- current_divisor++;
- }
- else if(three_count == 3) {
- current_divisor += 4;
- three_count = 1;
- }
- else {
- current_divisor += 2;
- three_count++;
- }
- }
-
- if((current_divisor > num) ||
- (current_divisor > denom)) {
- break;
- }
- }
-
- /* all calculations are done on positive num, since it's not
- * well defined what % does for negative values */
- out.num = (in.num < 0) ? (- num) : num;
- out.denom = denom;
- return out;
-}
-#endif
-
/********************************************************************
* double_to_gnc_numeric
********************************************************************/
@@ -1216,7 +1147,8 @@
********************************************************************/
gchar *
-gnc_numeric_to_string(gnc_numeric n) {
+gnc_numeric_to_string(gnc_numeric n)
+{
gchar *result;
long long int tmpnum = n.num;
long long int tmpdenom = n.denom;
More information about the gnucash-changes
mailing list