MySQL Lists are EOL. Please join:

List:Commits« Previous MessageNext Message »
From:Alexey Kopytov Date:September 21 2006 11:00am
Subject:bk commit into 4.1 tree (kaa:1.2541) BUG#22129
View as plain text  
Below is the list of changes that have just been committed into a local
4.1 repository of kaa. When kaa does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet@stripped, 2006-09-21 15:00:37+04:00, kaa@stripped +3 -0
  Fixed bug #22129: A small double precision number becomes zero
  Better checks for underflow/overflow

  mysql-test/r/type_float.result@stripped, 2006-09-21 15:00:35+04:00, kaa@stripped +7 -0
    Added testcase for bug #22129

  mysql-test/t/type_float.test@stripped, 2006-09-21 15:00:35+04:00, kaa@stripped +13 -1
    Added testcase for bug #22129

  strings/strtod.c@stripped, 2006-09-21 15:00:35+04:00, kaa@stripped +44 -25
    Fixed bug #22129: A small double precision number becomes zero
    Better checks for underflow/overflow

# This is a BitKeeper patch.  What follows are the unified diffs for the
# set of deltas contained in the patch.  The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User:	kaa
# Host:	polly.local
# Root:	/tmp/22129/bug22129/my41-bug22129

--- 1.17/strings/strtod.c	2006-09-21 15:00:41 +04:00
+++ 1.18/strings/strtod.c	2006-09-21 15:00:41 +04:00
@@ -30,7 +30,8 @@
 #include <m_ctype.h>
 
 #define MAX_DBL_EXP	308
-#define MAX_RESULT_FOR_MAX_EXP 1.79769313486232
+#define MAX_RESULT_FOR_MAX_EXP 1.7976931348623157
+#define MIN_RESULT_FOR_MIN_EXP 2.225073858507202
 static double scaler10[] = {
   1.0, 1e10, 1e20, 1e30, 1e40, 1e50, 1e60, 1e70, 1e80, 1e90
 };
@@ -57,10 +58,11 @@ double my_strtod(const char *str, char *
 {
   double result= 0.0;
   uint negative= 0, ndigits, dec_digits= 0, neg_exp= 0;
-  int exp= 0, digits_after_dec_point= 0;
+  int exp= 0, digits_after_dec_point= 0, tmp;
   const char *old_str, *end= *end_ptr, *start_of_number;
   char next_char;
   my_bool overflow=0;
+  double scaler= 1.0;
 
   *error= 0;
   if (str >= end)
@@ -91,6 +93,7 @@ double my_strtod(const char *str, char *
   while ((next_char= *str) >= '0' && next_char <= '9')
   {
     result= result*10.0 + (next_char - '0');
+    scaler= scaler*10.0;
     if (++str == end)
     {
       next_char= 0;                             /* Found end of string */
@@ -114,6 +117,7 @@ double my_strtod(const char *str, char *
     {
       result= result*10.0 + (next_char - '0');
       digits_after_dec_point++;
+      scaler= scaler*10.0;
       if (++str == end)
       {
         next_char= 0;
@@ -144,39 +148,54 @@ double my_strtod(const char *str, char *
       } while (str < end && my_isdigit(&my_charset_latin1, *str));
     }
   }
-  if ((exp= (neg_exp ? exp + digits_after_dec_point :
-             exp - digits_after_dec_point)))
+  tmp= neg_exp ? exp + digits_after_dec_point : exp - digits_after_dec_point;
+  if (tmp)
   {
-    double scaler;
-    if (exp < 0)
-    {
-      exp= -exp;
-      neg_exp= 1;                               /* neg_exp was 0 before */
-    }
-    if (exp + ndigits >= MAX_DBL_EXP + 1 && result)
-    {
-      /*
-        This is not 100 % as we actually will give an owerflow for
-        17E307 but not for 1.7E308 but lets cut some corners to make life
-        simpler
-      */
-      if (exp + ndigits > MAX_DBL_EXP + 1 ||
-          result >= MAX_RESULT_FOR_MAX_EXP)
+    int order;
+    /*
+      Check for underflow/overflow.
+      order is such an integer number that f = C * 10 ^ order,
+      where f is the resulting floating point number and 1 <= C < 10.
+      Here we compute the modulus
+    */
+    order= exp + (neg_exp ? -1 : 1) * (ndigits - 1);
+    if (order < 0)
+      order= -order;
+    if (order >= MAX_DBL_EXP && result)
+    {
+      double c;
+      /* Compute modulus of C (see comment above) */
+      c= result / scaler * 10.0;
+      if (neg_exp)
       {
-        if (neg_exp)
+        if (order > MAX_DBL_EXP || c < MIN_RESULT_FOR_MIN_EXP)
+        {
           result= 0.0;
-        else
+          goto done;
+        }
+      }
+      else
+      {
+        if (order > MAX_DBL_EXP || c > MAX_RESULT_FOR_MAX_EXP)
+        {
           overflow= 1;
-        goto done;
+          goto done;
+        }
       }
     }
-    scaler= 1.0;
+
+    exp= tmp;
+    if (exp < 0)
+    {
+      exp= -exp;
+      neg_exp= 1;                               /* neg_exp was 0 before */
+    }
     while (exp >= 100)
     {
-      scaler*= 1.0e100;
+      result= neg_exp ? result/1.0e100 : result*1.0e100;
       exp-= 100;
     }
-    scaler*= scaler10[exp/10]*scaler1[exp%10];
+    scaler= scaler10[exp/10]*scaler1[exp%10];
     if (neg_exp)
       result/= scaler;
     else

--- 1.35/mysql-test/r/type_float.result	2006-09-21 15:00:41 +04:00
+++ 1.36/mysql-test/r/type_float.result	2006-09-21 15:00:41 +04:00
@@ -272,3 +272,10 @@ desc t3;
 Field	Type	Null	Key	Default	Extra
 a	double			0	
 drop table t1,t2,t3;
+select 1e-308, 1.00000001e-300, 100000000e-300;
+1e-308	1.00000001e-300	100000000e-300
+0	1.00000001e-300	1e-292
+select 10e307;
+10e307
+1e+308
+End of 4.1 tests

--- 1.21/mysql-test/t/type_float.test	2006-09-21 15:00:41 +04:00
+++ 1.22/mysql-test/t/type_float.test	2006-09-21 15:00:41 +04:00
@@ -179,4 +179,16 @@ show warnings;
 desc t3;
 drop table t1,t2,t3;
 
-# End of 4.1 tests
+#
+# Bug #22129: A small double precision number becomes zero
+# - check if underflows are detected correctly
+#
+select 1e-308, 1.00000001e-300, 100000000e-300;
+
+#
+# Bug #22129: A small double precision number becomes zero
+# - check if overflows are detected correctly
+#
+select 10e307;
+
+--echo End of 4.1 tests
Thread
bk commit into 4.1 tree (kaa:1.2541) BUG#22129Alexey Kopytov21 Sep