From: Date: September 21 2006 1:00pm Subject: bk commit into 4.1 tree (kaa:1.2541) BUG#22129 List-Archive: http://lists.mysql.com/commits/12329 X-Bug: 22129 Message-Id: <20060921110041.B88E3C217F@polly.local> 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 #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