[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    kdeutils/kcalc
From:       Klaus Niederkrüger <kniederk () mi ! uni-koeln ! de>
Date:       2005-01-24 0:39:43
Message-ID: 20050124003943.F33051BA82 () office ! kde ! org
[Download RAW message or body]

CVS commit by kniederk: 

I hope this fixes the rounding problem. Please control this patch if you have time \
(and know about floating points). Thanks


  M +29 -14    kcalc_core.cpp   1.97
  M +3 -1      kcalctype.h   1.23


--- kdeutils/kcalc/kcalc_core.cpp  #1.96:1.97
@@ -213,11 +213,19 @@ static CALCAMNT ExecAdd(CALCAMNT left_op
         // printf("ExecAdd\n");
         CALCAMNT tmp_result = left_op + right_op;
-        // Set result to zero, when smaller than FPU-precision
-        CALCAMNT tmp_divisor = FABS(left_op) + FABS(right_op);
-        if (tmp_divisor != 0L  &&
-            FABS(tmp_result)/tmp_divisor > 2*CALCAMNT_EPSILON)
-                return tmp_result;
-        else
-                return 0L;       
+
+        // When operating with floating point numbers the following
+        // effect can happen: 1.0000001 + (-1.0) gives 1.0000232e-6
+        // instead of 1e-6. This looks very bad on a calculator (to
+        // the unexperienced eye). Hence we round in this case.
+        CALCAMNT max_precision = (FABS(left_op) + FABS(right_op))
+          * CALCAMNT_EPSILON;
+        // we want to round to decimal digits, hence we need to find
+        // the number of valid digits
+        CALCAMNT digits = 1;
+        while (digits > max_precision)
+          digits *= 0.1L;
+        digits *= 100.0L; // this number is experimental
+
+        return  digits * ROUND(tmp_result/digits);
 }
 
@@ -226,11 +234,18 @@ static CALCAMNT ExecSubtract(CALCAMNT le
         // printf("ExecSubtract\n");
         CALCAMNT tmp_result = left_op - right_op;
-        // Set result to zero, when smaller than FPU-precision
-        CALCAMNT tmp_divisor = FABS(left_op) + FABS(right_op);
-        if (tmp_divisor != 0L  &&
-            FABS(tmp_result)/tmp_divisor > 2*CALCAMNT_EPSILON)
-                return tmp_result;
-        else
-                return 0L;       
+        // When operating with floating point numbers the following
+        // effect can happen: 1.0000001 + (-1.0) gives 1.0000232e-6
+        // instead of 1e-6. This looks very bad on a calculator (to
+        // the unexperienced eye). Hence we round in this case.
+        CALCAMNT max_precision = (FABS(left_op) + FABS(right_op))
+          * CALCAMNT_EPSILON;
+        // we want to round to decimal digits, hence we need to find
+        // the number of valid digits
+        CALCAMNT digits = 1;
+        while (digits > max_precision)
+          digits *= 0.1L;
+        digits *= 100.0L; // this number is experimental
+
+        return  digits * ROUND(tmp_result/digits);
 }
 

--- kdeutils/kcalc/kcalctype.h  #1.22:1.23
@@ -74,4 +74,5 @@
         #define ISINF(X)        isinfl(X)
         #define STRTOD(X,Y)     strtold(X,Y)
+        #define ROUND(X)        roundl(X)
         #define CALCAMNT_EPSILON        LDBL_EPSILON
 #else
@@ -99,4 +100,5 @@
         #define ISINF(X)        isinf(X)
         #define STRTOD(X,Y)     strtod(X,Y)
+        #define ROUND(X)        round(X)
         #define CALCAMNT_EPSILON        DBL_EPSILON
 #endif


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic