diff options
author | unknown <kaa@polly.local> | 2006-09-22 19:40:07 +0400 |
---|---|---|
committer | unknown <kaa@polly.local> | 2006-09-22 19:40:07 +0400 |
commit | 0c72b05a83a54ef86957ad03d73aa96b4c05e252 (patch) | |
tree | dc6964369953cd56a9f12f9740b7a9a452e1a7b5 /strings | |
parent | 17bda20821e3d885456ec2fe80e87a4ca5a5c25e (diff) | |
parent | 2299727e604c4a04a586d5baa579028040ace8db (diff) | |
download | mariadb-git-0c72b05a83a54ef86957ad03d73aa96b4c05e252.tar.gz |
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
Diffstat (limited to 'strings')
-rw-r--r-- | strings/strtod.c | 67 |
1 files changed, 43 insertions, 24 deletions
diff --git a/strings/strtod.c b/strings/strtod.c index 7171a6e0801..ddb570718a0 100644 --- a/strings/strtod.c +++ b/strings/strtod.c @@ -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 **end_ptr, int *error) { 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_exp; 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 **end_ptr, int *error) 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 **end_ptr, int *error) { 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 **end_ptr, int *error) } while (str < end && my_isdigit(&my_charset_latin1, *str)); } } - if ((exp= (neg_exp ? exp + digits_after_dec_point : - exp - digits_after_dec_point))) + tmp_exp= neg_exp ? exp + digits_after_dec_point : exp - digits_after_dec_point; + if (tmp_exp) { - double scaler; - if (exp < 0) - { - exp= -exp; - neg_exp= 1; /* neg_exp was 0 before */ - } - if (exp + ndigits >= MAX_DBL_EXP + 1 && result) + 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) { - /* - 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) + 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_exp; + 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 |