summaryrefslogtreecommitdiff
path: root/strings
diff options
context:
space:
mode:
authorunknown <kaa@polly.local>2006-09-22 19:46:09 +0400
committerunknown <kaa@polly.local>2006-09-22 19:46:09 +0400
commit09e8459a020bcc6e101ba11a50f680ccc4a1d3ee (patch)
treec7b60e77962ac901dc4bfb390fd8f00d20f34d8f /strings
parentc7e0e1b1693d202aea187f867df2be98a352b28e (diff)
parent0c72b05a83a54ef86957ad03d73aa96b4c05e252 (diff)
downloadmariadb-git-09e8459a020bcc6e101ba11a50f680ccc4a1d3ee.tar.gz
Merge polly.local:/tmp/22129/bug22129/my50-bug22129
into polly.local:/home/kaa/src/maint/m50-maint--07OGt
Diffstat (limited to 'strings')
-rw-r--r--strings/strtod.c67
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