gcalctool r2311 - in trunk: . gcalctool



Author: rancell
Date: Sun Nov 23 09:55:42 2008
New Revision: 2311
URL: http://svn.gnome.org/viewvc/gcalctool?rev=2311&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:
   trunk/ChangeLog
   trunk/gcalctool/mpmath.c
   trunk/gcalctool/mpmath.h
   trunk/gcalctool/unittest.c

Modified: trunk/gcalctool/mpmath.c
==============================================================================
--- trunk/gcalctool/mpmath.c	(original)
+++ trunk/gcalctool/mpmath.c	Sun Nov 23 09:55:42 2008
@@ -32,87 +32,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, 16, 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);    
 }
 
 
@@ -126,18 +134,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, 16, 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, 16, t1);
 }
 
 void
@@ -294,34 +312,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);
 }
 
 
@@ -432,7 +468,7 @@
  */
 
 void
-make_fixed(char *target, int target_len, const 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];
@@ -559,7 +595,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];
@@ -624,7 +660,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: trunk/gcalctool/mpmath.h
==============================================================================
--- trunk/gcalctool/mpmath.h	(original)
+++ trunk/gcalctool/mpmath.h	Sun Nov 23 09:55:42 2008
@@ -25,13 +25,6 @@
 #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 };
@@ -67,7 +60,7 @@
 is_natural(int MPnum[MP_SIZE]);
 
 // FIXME: These should be merged together
-void make_fixed(char *, int, const 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: trunk/gcalctool/unittest.c
==============================================================================
--- trunk/gcalctool/unittest.c	(original)
+++ trunk/gcalctool/unittest.c	Sun Nov 23 09:55:42 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
@@ -66,7 +66,7 @@
     test("256", "256", 0);
     test("1.00", "1", 0);
     test("1.01", "1.01", 0);
-    test("pi", "3.1415926", 0);
+    test("pi", "3.141592654", 0);
     test("1e+3", "1000", 0);
     test("1e-3", "0.001", 0);
     test("1e9", "1000000000", 0);
@@ -111,7 +111,7 @@
     //FIXME: Need to update do_factorial() test("-1!", "", 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]