gcalctool r2310 - in branches/gnome-2-24: . gcalctool



Author: rancell
Date: Sun Nov 23 09:54:51 2008
New Revision: 2310
URL: http://svn.gnome.org/viewvc/gcalctool?rev=2310&view=rev

Log:
Removed double conversion in boolean and 32 bit and 16 bit mask operations so they can handle larger numbers (Robert Ancell, Bug #509988)

Modified:
   branches/gnome-2-24/ChangeLog
   branches/gnome-2-24/gcalctool/mpmath.c
   branches/gnome-2-24/gcalctool/mpmath.h
   branches/gnome-2-24/gcalctool/unittest.c

Modified: branches/gnome-2-24/gcalctool/mpmath.c
==============================================================================
--- branches/gnome-2-24/gcalctool/mpmath.c	(original)
+++ branches/gnome-2-24/gcalctool/mpmath.c	Sun Nov 23 09:54:51 2008
@@ -14,8 +14,7 @@
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- *  02111-1307, USA.
- */
+ *  02111-1307, USA. */
 
 #include <assert.h>
 #include <errno.h>
@@ -31,87 +30,95 @@
     2.582249878e+120    /* Hexadecimal. */
 };
 
-BOOLEAN
-ibool(double x)
-{
-    BOOLEAN p = (BOOLEAN) x;
 
-    return(p);
+static int hex_to_int(char digit)
+{
+    if (digit >= '0' && digit <= '9')
+        return digit - '0';
+    if (digit >= 'A' && digit <= 'F')
+        return digit - 'A' + 10;
+    if (digit >= 'a' && digit <= 'f')
+        return digit - 'a' + 10;
+    return 0;
 }
 
 
-double
-setbool(BOOLEAN p)
+static void
+calc_bitwise(const int s1[MP_SIZE], const int s2[MP_SIZE], int (*bitwise_operator)(int, int), int t[MP_SIZE])
 {
-    BOOLEAN q;
-    double val;
-
-    q = p & 0x80000000;
-    p &= 0x7fffffff;
-    val = p;
-    if (q) {
-        val += 2147483648.0;
+    char text1[MAX_DIGITS], text2[MAX_DIGITS], text_out[MAX_DIGITS];
+    int offset1, offset2, offset_out;
+    
+    make_fixed(text1, MAX_DIGITS, s1, HEX, MAX_DIGITS);
+    make_fixed(text2, MAX_DIGITS, s2, HEX, MAX_DIGITS);
+    offset1 = strlen(text1) - 1;
+    offset2 = strlen(text2) - 1;
+    offset_out = offset1 > offset2 ? offset1 : offset2;
+    
+    /* Be at least 32 bits wide so inverse operations make sense */
+    if (offset_out < 7)
+        offset_out = 7;
+
+    /* Perform bitwise operator on each character from right to left */
+    for (text_out[offset_out+1] = '\0'; offset_out >= 0; offset_out--) {
+        int v1 = 0, v2 = 0;
+
+        if (offset1 >= 0) {
+            v1 = hex_to_int(text1[offset1]);
+            offset1--;
+        }
+        if (offset2 >= 0) {
+            v2 = hex_to_int(text2[offset2]);
+            offset2--;
+        }
+        text_out[offset_out] = digits[bitwise_operator(v1, v2)];
     }
-
-    return(val);
+    
+    MPstr_to_num(text_out, HEX, t);
 }
 
 
+static int calc_bitwise_and(int v1, int v2) { return v1 & v2; }
+static int calc_bitwise_or(int v1, int v2) { return v1 | v2; }
+static int calc_bitwise_xor(int v1, int v2) { return v1 ^ v2; }
+static int calc_bitwise_xnor(int v1, int v2) { return v1 ^ v2 ^ 0xF; }
+static int calc_bitwise_not(int v1, int dummy) { return v1 ^ 0xF; }
+
+
 void
 calc_and(const int s1[MP_SIZE], const int s2[MP_SIZE], int t[MP_SIZE])
 {
-    double dres, dval;
-
-    dres = mp_cast_to_double(s1);
-    dval = mp_cast_to_double(s2);
-    dres = setbool(ibool(dres) & ibool(dval));
-    mp_set_from_double(dres, t);
+    calc_bitwise(s1, s2, calc_bitwise_and, t);
 }
 
 
 void
 calc_or(const int s1[MP_SIZE], const int s2[MP_SIZE], int t[MP_SIZE])
 {
-    double dres, dval;
-
-    dres = mp_cast_to_double(s1);
-    dval = mp_cast_to_double(s2);
-    dres = setbool(ibool(dres) | ibool(dval));
-    mp_set_from_double(dres, t);
+    calc_bitwise(s1, s2, calc_bitwise_or, t);
 }
 
 
 void
 calc_xor(const int s1[MP_SIZE], const int s2[MP_SIZE], int t[MP_SIZE])
 {
-    double dres, dval;
-
-    dres = mp_cast_to_double(s1);
-    dval = mp_cast_to_double(s2);
-    dres = setbool(ibool(dres) ^ ibool(dval));
-    mp_set_from_double(dres, t);
+    calc_bitwise(s1, s2, calc_bitwise_xor, t);
 }
 
 
 void
 calc_xnor(const int s1[MP_SIZE], const int s2[MP_SIZE], int t[MP_SIZE])
 {
-    double dres, dval;
-
-    dres = mp_cast_to_double(s1);
-    dval = mp_cast_to_double(s2);
-    dres = setbool(~ibool(dres) ^ ibool(dval));
-    mp_set_from_double(dres, t);
+    calc_bitwise(s1, s2, calc_bitwise_xnor, t);
 }
 
 
 void
 calc_not(const int s1[MP_SIZE], int t[MP_SIZE])
 {
-    double dval = mp_cast_to_double(s1);
-    
-    dval = setbool(~ibool(dval));
-    mp_set_from_double(dval, t);
+    int dummy[MP_SIZE];
+    mp_set_from_integer(0, dummy);
+    calc_bitwise(s1, dummy, calc_bitwise_not, t);    
 }
 
 
@@ -125,18 +132,28 @@
 void
 calc_u32(const int s1[MP_SIZE], int t1[MP_SIZE])
 {
-    double dval = mp_cast_to_double(s1);
-    dval = setbool(ibool(dval));
-    mp_set_from_double(dval, t1);
+    char text[MAX_DIGITS];
+    size_t len, offset;
+    
+    /* Convert to a hexadecimal string and use last 8 characters */
+    make_fixed(text, MAX_DIGITS, s1, HEX, MAX_DIGITS);
+    len = strlen(text);
+    offset = len > 8 ? len - 8: 0;
+    MPstr_to_num(text + offset, HEX, t1);
 }
 
 
 void
 calc_u16(const int s1[MP_SIZE], int t1[MP_SIZE])
 {
-    double dval = mp_cast_to_double(s1);
-    dval = setbool(ibool(dval) & 0xffff);
-    mp_set_from_double(dval, t1);
+    char text[MAX_DIGITS];
+    size_t len, offset;
+    
+    /* Convert to a hexadecimal string and use last 4 characters */
+    make_fixed(text, MAX_DIGITS, s1, HEX, MAX_DIGITS);
+    len = strlen(text);
+    offset = len > 4 ? len - 4: 0;
+    MPstr_to_num(text + offset, HEX, t1);
 }
 
 
@@ -201,8 +218,8 @@
 
 int
 calc_modulus(int op1[MP_SIZE], 
-	     int op2[MP_SIZE], 
-	     int result[MP_SIZE])
+             int op2[MP_SIZE], 
+             int result[MP_SIZE])
 {
     int MP1[MP_SIZE], MP2[MP_SIZE];
 
@@ -217,8 +234,8 @@
 
     mp_set_from_integer(0, MP1);
     if ((mp_is_less_than(op2, MP1)
-	 && mp_is_greater_than(result, MP1)) ||
-	mp_is_less_than(result, MP1)) { 
+         && mp_is_greater_than(result, MP1)) ||
+        mp_is_less_than(result, MP1)) { 
         mp_add(result, op2, result);
     }
 
@@ -673,34 +690,52 @@
 void
 calc_shift(int s[MP_SIZE], int t[MP_SIZE], int times)
 {
-  /* Implementation derived from old code.
-   * Using BOOLEAN is strange at least. Assumed that
-   * boolean means BINARY representation
-   */
-
-    BOOLEAN temp;
-    double dval = mp_cast_to_double(s);
-    temp = ibool(dval);
-
-    /* There is a reason to do shift like this. Reason is that
-     * processors define shift only in a certain range. i386 uses only 5
-     * bits to describe shiftable amount. So, shift 32 times gives original
-     * number. That can cause very strange results (and bugs).
-     */
+    char text[MAX_DIGITS+1], text_out[MAX_DIGITS];
+    size_t i, length, out_length;
+    int upper_offset, lower_offset;
 
-    if (times > 0)
-    {
-        while (times--) {
-            temp = temp << 1;
-        }
+    make_fixed(text, MAX_DIGITS+1, s, HEX, MAX_DIGITS);
+    length = out_length = strlen(text);
+    
+    /* How many nibbles we are offset by */
+    if (times >= 0) {
+        upper_offset = times/4;
+        lower_offset = upper_offset + 1;
     } else {
-        while (times++) {
-            temp = temp >> 1;
+        lower_offset = times/4;
+        upper_offset = lower_offset - 1;
+    }
+    
+    /* If shifting left need more space for digits */
+    if (times >= 0) {
+        size_t extra = (times+3) / 4; 
+        out_length += extra;
+        upper_offset -= extra;
+        lower_offset -= extra;
+        if (out_length > MAX_DIGITS)
+            return; // FIXME
+    }
+       
+    for (i = 0; i < out_length; i++) {
+        int upper_bits = 0, lower_bits = 0;
+        
+        if (i+upper_offset >= 0 && i+upper_offset < length)
+            upper_bits = hex_to_int(text[i+upper_offset]);
+        if (i+lower_offset >= 0 && i+lower_offset < length)
+            lower_bits = hex_to_int(text[i+lower_offset]);
+        
+        if (times >= 0) {
+            upper_bits <<= times % 4;
+            lower_bits >>= 4 - (times % 4);
+        } else {
+            upper_bits <<= 4 - (-times % 4);
+            lower_bits >>= -times % 4;
         }
+        text_out[i] = digits[(upper_bits | lower_bits) & 0xF];
     }
-
-    dval = setbool(temp);
-    mp_set_from_double(dval, t);
+    text_out[i] = '\0';
+    
+    MPstr_to_num(text_out, HEX, t);
 }
 
 
@@ -811,7 +846,7 @@
  */
 
 void
-make_fixed(char *target, int target_len, int *MPnumber, int base, int cmax, int toclear)
+make_fixed(char *target, int target_len, const int *MPnumber, int base, int cmax)
 {
     char half[MAXLINE], *optr;
     int MP1base[MP_SIZE], MP1[MP_SIZE], MP2[MP_SIZE], MPval[MP_SIZE];
@@ -883,7 +918,7 @@
 /* Convert engineering or scientific number in the given base. */
 
 void
-make_eng_sci(char *target, int target_len, int *MPnumber, int base)
+make_eng_sci(char *target, int target_len, const int *MPnumber, int base)
 {
     char half[MAXLINE], fixed[MAX_DIGITS], *optr;
     int MP1[MP_SIZE], MPatmp[MP_SIZE], MPval[MP_SIZE];
@@ -938,7 +973,7 @@
         }
     }
  
-    make_fixed(fixed, MAX_DIGITS, MPmant, base, MAX_DIGITS-6, TRUE);
+    make_fixed(fixed, MAX_DIGITS, MPmant, base, MAX_DIGITS-6);
     len = strlen(fixed);
     for (i = 0; i < len; i++) {
         *optr++ = fixed[i];
@@ -979,7 +1014,7 @@
 /* Convert MP number to character string in the given base. */
 
 void
-make_number(char *target, int target_len, int *MPnumber, int base, int ignoreError)
+make_number(char *target, int target_len, const int *MPnumber, int base, int ignoreError)
 {
     double val;
     
@@ -1003,7 +1038,7 @@
         (v->dtype == FIX && val != 0.0 && (val > max_fix[base]))) {
         make_eng_sci(target, target_len, MPnumber, base);
     } else {
-        make_fixed(target, target_len, MPnumber, base, MAX_DIGITS, TRUE);
+        make_fixed(target, target_len, MPnumber, base, MAX_DIGITS);
     }
 }
 

Modified: branches/gnome-2-24/gcalctool/mpmath.h
==============================================================================
--- branches/gnome-2-24/gcalctool/mpmath.h	(original)
+++ branches/gnome-2-24/gcalctool/mpmath.h	Sun Nov 23 09:54:51 2008
@@ -25,16 +25,9 @@
 #include "mp.h"
 #include "calctool.h"
 
-typedef unsigned long  BOOLEAN;
-
-/* function parameters: t=target, s=source) */
-
-BOOLEAN ibool(double x);
-double setbool(BOOLEAN p);
-
 /* Trigonometric functions types */
-enum trigfunc_type { sin_t, cos_t, tan_t, sinh_t, cosh_t, tanh_t,
-		     asin_t, acos_t, atan_t, asinh_t, acosh_t, atanh_t };
+enum trigfunc_type { sin_t,   cos_t,  tan_t,  sinh_t,  cosh_t,  tanh_t,
+                     asin_t, acos_t, atan_t, asinh_t, acosh_t, atanh_t };
 
 int calc_trigfunc(enum trigfunc_type type, int s1[MP_SIZE], int t1[MP_SIZE]);
 
@@ -80,7 +73,7 @@
 // FIXME: These should be merged together
 void MPstr_to_num(const char *, enum base_type, int *);
 void mp_set_from_string(const char *number, int t[MP_SIZE]);
-void make_fixed(char *, int, int *, int, int, int);
-void make_number(char *, int, int *, int, int);
+void make_fixed(char *, int, const int *, int, int);
+void make_number(char *, int, const int *, int, int);
 
 #endif /*MPMATH_H*/

Modified: branches/gnome-2-24/gcalctool/unittest.c
==============================================================================
--- branches/gnome-2-24/gcalctool/unittest.c	(original)
+++ branches/gnome-2-24/gcalctool/unittest.c	Sun Nov 23 09:54:51 2008
@@ -44,7 +44,7 @@
         return;
     }
     
-    make_fixed(result_str, MAXLINE, result, DEC, 10, FALSE);   
+    make_fixed(result_str, MAXLINE, result, DEC, 100);
     if(strcmp(result_str, expected) != 0)
         printf("FAIL: '%s' -> '%s', expected '%s'\n", expression, result_str, expected);
     else
@@ -101,7 +101,7 @@
     test("(-10)^2", "100", 0);    
 
     test("Sqrt(4)", "2", 0);
-    test("Sqrt(2)", "1.4142135", 0);
+    test("Sqrt(2)", "1.414213562", 0);
     
     test("Int(3.2)", "3", 0);
     test("Frac(3.2)", "0.2", 0);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]