Commit 0c72b05a authored by unknown's avatar unknown

Merge polly.local:/tmp/22129/bug22129/my41-bug22129

into  polly.local:/tmp/22129/bug22129/my50-bug22129


strings/strtod.c:
  Auto merged
mysql-test/r/type_float.result:
  SCCS merged
mysql-test/t/type_float.test:
  SCCS merged
parents 17bda208 2299727e
...@@ -262,6 +262,13 @@ desc t3; ...@@ -262,6 +262,13 @@ desc t3;
Field Type Null Key Default Extra Field Type Null Key Default Extra
a decimal(21,2) NO 0.00 a decimal(21,2) NO 0.00
drop table t1,t2,t3; 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
create table t1 (s1 float(0,2)); create table t1 (s1 float(0,2));
ERROR 42000: For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column 's1'). ERROR 42000: For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column 's1').
create table t1 (s1 float(1,2)); create table t1 (s1 float(1,2));
......
...@@ -178,7 +178,16 @@ show warnings; ...@@ -178,7 +178,16 @@ show warnings;
desc t3; desc t3;
drop table t1,t2,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;
# check if overflows are detected correctly
select 10e307;
--echo End of 4.1 tests
# #
# bug #12694 (float(m,d) specifications) # bug #12694 (float(m,d) specifications)
......
...@@ -30,7 +30,8 @@ ...@@ -30,7 +30,8 @@
#include "m_ctype.h" #include "m_ctype.h"
#define MAX_DBL_EXP 308 #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[] = { static double scaler10[] = {
1.0, 1e10, 1e20, 1e30, 1e40, 1e50, 1e60, 1e70, 1e80, 1e90 1.0, 1e10, 1e20, 1e30, 1e40, 1e50, 1e60, 1e70, 1e80, 1e90
}; };
...@@ -57,10 +58,11 @@ double my_strtod(const char *str, char **end_ptr, int *error) ...@@ -57,10 +58,11 @@ double my_strtod(const char *str, char **end_ptr, int *error)
{ {
double result= 0.0; double result= 0.0;
uint negative= 0, ndigits, dec_digits= 0, neg_exp= 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_exp;
const char *old_str, *end= *end_ptr, *start_of_number; const char *old_str, *end= *end_ptr, *start_of_number;
char next_char; char next_char;
my_bool overflow=0; my_bool overflow=0;
double scaler= 1.0;
*error= 0; *error= 0;
if (str >= end) if (str >= end)
...@@ -91,6 +93,7 @@ double my_strtod(const char *str, char **end_ptr, int *error) ...@@ -91,6 +93,7 @@ double my_strtod(const char *str, char **end_ptr, int *error)
while ((next_char= *str) >= '0' && next_char <= '9') while ((next_char= *str) >= '0' && next_char <= '9')
{ {
result= result*10.0 + (next_char - '0'); result= result*10.0 + (next_char - '0');
scaler= scaler*10.0;
if (++str == end) if (++str == end)
{ {
next_char= 0; /* Found end of string */ next_char= 0; /* Found end of string */
...@@ -114,6 +117,7 @@ double my_strtod(const char *str, char **end_ptr, int *error) ...@@ -114,6 +117,7 @@ double my_strtod(const char *str, char **end_ptr, int *error)
{ {
result= result*10.0 + (next_char - '0'); result= result*10.0 + (next_char - '0');
digits_after_dec_point++; digits_after_dec_point++;
scaler= scaler*10.0;
if (++str == end) if (++str == end)
{ {
next_char= 0; next_char= 0;
...@@ -144,39 +148,54 @@ double my_strtod(const char *str, char **end_ptr, int *error) ...@@ -144,39 +148,54 @@ double my_strtod(const char *str, char **end_ptr, int *error)
} while (str < end && my_isdigit(&my_charset_latin1, *str)); } while (str < end && my_isdigit(&my_charset_latin1, *str));
} }
} }
if ((exp= (neg_exp ? exp + digits_after_dec_point : tmp_exp= neg_exp ? exp + digits_after_dec_point : exp - digits_after_dec_point;
exp - digits_after_dec_point))) if (tmp_exp)
{ {
double scaler; int order;
if (exp < 0) /*
{ Check for underflow/overflow.
exp= -exp; order is such an integer number that f = C * 10 ^ order,
neg_exp= 1; /* neg_exp was 0 before */ where f is the resulting floating point number and 1 <= C < 10.
} Here we compute the modulus
if (exp + ndigits >= MAX_DBL_EXP + 1 && result) */
order= exp + (neg_exp ? -1 : 1) * (ndigits - 1);
if (order < 0)
order= -order;
if (order >= MAX_DBL_EXP && result)
{ {
/* double c;
This is not 100 % as we actually will give an owerflow for /* Compute modulus of C (see comment above) */
17E307 but not for 1.7E308 but lets cut some corners to make life c= result / scaler * 10.0;
simpler if (neg_exp)
*/
if (exp + ndigits > MAX_DBL_EXP + 1 ||
result >= MAX_RESULT_FOR_MAX_EXP)
{ {
if (neg_exp) if (order > MAX_DBL_EXP || c < MIN_RESULT_FOR_MIN_EXP)
{
result= 0.0; result= 0.0;
else goto done;
}
}
else
{
if (order > MAX_DBL_EXP || c > MAX_RESULT_FOR_MAX_EXP)
{
overflow= 1; overflow= 1;
goto done; goto done;
}
} }
} }
scaler= 1.0;
exp= tmp_exp;
if (exp < 0)
{
exp= -exp;
neg_exp= 1; /* neg_exp was 0 before */
}
while (exp >= 100) while (exp >= 100)
{ {
scaler*= 1.0e100; result= neg_exp ? result/1.0e100 : result*1.0e100;
exp-= 100; exp-= 100;
} }
scaler*= scaler10[exp/10]*scaler1[exp%10]; scaler= scaler10[exp/10]*scaler1[exp%10];
if (neg_exp) if (neg_exp)
result/= scaler; result/= scaler;
else else
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment