mirror of
https://github.com/MariaDB/server.git
synced 2025-01-17 20:42:30 +01:00
4443e76696
error with the IBM xlc_r compiler strings/strtod.c: - No C++ comments in .c files, please...
140 lines
3 KiB
C
140 lines
3 KiB
C
/*
|
|
An alternative implementation of "strtod()" that is both
|
|
simplier, and thread-safe.
|
|
|
|
From mit-threads as bundled with MySQL 3.22
|
|
|
|
SQL:2003 specifies a number as
|
|
|
|
<signed numeric literal> ::= [ <sign> ] <unsigned numeric literal>
|
|
|
|
<unsigned numeric literal> ::=
|
|
<exact numeric literal>
|
|
| <approximate numeric literal>
|
|
|
|
<exact numeric literal> ::=
|
|
<unsigned integer> [ <period> [ <unsigned integer> ] ]
|
|
| <period> <unsigned integer>
|
|
|
|
<approximate numeric literal> ::= <mantissa> E <exponent>
|
|
|
|
<mantissa> ::= <exact numeric literal>
|
|
|
|
<exponent> ::= <signed integer>
|
|
|
|
So do we.
|
|
|
|
*/
|
|
|
|
#include "my_base.h"
|
|
#include "m_ctype.h"
|
|
|
|
static double scaler10[] = {
|
|
1.0, 1e10, 1e20, 1e30, 1e40, 1e50, 1e60, 1e70, 1e80, 1e90
|
|
};
|
|
static double scaler1[] = {
|
|
1.0, 10.0, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9
|
|
};
|
|
|
|
/* let's use a static array for not to accumulate the error */
|
|
static double pastpoint[] = {
|
|
1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 1e-7, 1e-8, 1e-9,
|
|
1e-10, 1e-11, 1e-12, 1e-13, 1e-14, 1e-15, 1e-16, 1e-17, 1e-18, 1e-19,
|
|
1e-20, 1e-21, 1e-22, 1e-23, 1e-24, 1e-25, 1e-26, 1e-27, 1e-28, 1e-29,
|
|
1e-30, 1e-31, 1e-32, 1e-33, 1e-34, 1e-35, 1e-36, 1e-37, 1e-38, 1e-39,
|
|
1e-40, 1e-41, 1e-42, 1e-43, 1e-44, 1e-45, 1e-46, 1e-47, 1e-48, 1e-49,
|
|
1e-50, 1e-51, 1e-52, 1e-53, 1e-54, 1e-55, 1e-56, 1e-57, 1e-58, 1e-59,
|
|
};
|
|
|
|
double my_strtod(const char *str, char **end)
|
|
{
|
|
double result= 0.0;
|
|
int negative, ndigits;
|
|
const char *old_str;
|
|
|
|
while (my_isspace(&my_charset_latin1, *str))
|
|
str++;
|
|
|
|
if ((negative= (*str == '-')) || *str=='+')
|
|
str++;
|
|
|
|
old_str= str;
|
|
while (my_isdigit (&my_charset_latin1, *str))
|
|
{
|
|
result= result*10.0 + (*str - '0');
|
|
str++;
|
|
}
|
|
ndigits= str-old_str;
|
|
|
|
if (*str == '.')
|
|
{
|
|
int n= 0;
|
|
str++;
|
|
old_str= str;
|
|
while (my_isdigit (&my_charset_latin1, *str))
|
|
{
|
|
if (n < sizeof(pastpoint)/sizeof(pastpoint[0]))
|
|
{
|
|
result+= pastpoint[n] * (*str - '0');
|
|
n++;
|
|
}
|
|
str++;
|
|
}
|
|
ndigits+= str-old_str;
|
|
if (!ndigits) str--;
|
|
}
|
|
if (ndigits && (*str=='e' || *str=='E'))
|
|
{
|
|
int exp= 0;
|
|
int neg= 0;
|
|
const char *old_str= str++;
|
|
|
|
if ((neg= (*str == '-')) || *str == '+')
|
|
str++;
|
|
|
|
if (!my_isdigit (&my_charset_latin1, *str))
|
|
str= old_str;
|
|
else
|
|
{
|
|
double scaler= 1.0;
|
|
while (my_isdigit (&my_charset_latin1, *str))
|
|
{
|
|
exp= exp*10 + *str - '0';
|
|
str++;
|
|
}
|
|
if (exp >= 1000)
|
|
{
|
|
if (neg)
|
|
result= 0.0;
|
|
else
|
|
result= DBL_MAX;
|
|
goto done;
|
|
}
|
|
while (exp >= 100)
|
|
{
|
|
scaler*= 1.0e100;
|
|
exp-= 100;
|
|
}
|
|
scaler*= scaler10[exp/10]*scaler1[exp%10];
|
|
if (neg)
|
|
result/= scaler;
|
|
else
|
|
result*= scaler;
|
|
}
|
|
}
|
|
|
|
done:
|
|
if (end)
|
|
*end = (char *)str;
|
|
|
|
if (isinf(result))
|
|
result=DBL_MAX;
|
|
|
|
return negative ? -result : result;
|
|
}
|
|
|
|
double my_atof(const char *nptr)
|
|
{
|
|
return (strtod(nptr, 0));
|
|
}
|
|
|