Core: text->double conversion refactored / optimised

git-svn-id: svn://ultimatepp.org/upp/trunk@16002 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
cxl 2021-06-22 11:33:39 +00:00
parent 2583d221b8
commit 11a2c6f214
4 changed files with 61 additions and 99 deletions

View file

@ -2,23 +2,7 @@
namespace Upp {
double ipow10_table[] = {
1e-100, 1e-99, 1e-98, 1e-97, 1e-96, 1e-95, 1e-94, 1e-93, 1e-92, 1e-91, 1e-90, 1e-89, 1e-88,
1e-87, 1e-86, 1e-85, 1e-84, 1e-83, 1e-82, 1e-81, 1e-80, 1e-79, 1e-78, 1e-77, 1e-76, 1e-75,
1e-74, 1e-73, 1e-72, 1e-71, 1e-70, 1e-69, 1e-68, 1e-67, 1e-66, 1e-65, 1e-64, 1e-63, 1e-62,
1e-61, 1e-60, 1e-59, 1e-58, 1e-57, 1e-56, 1e-55, 1e-54, 1e-53, 1e-52, 1e-51, 1e-50, 1e-49,
1e-48, 1e-47, 1e-46, 1e-45, 1e-44, 1e-43, 1e-42, 1e-41, 1e-40, 1e-39, 1e-38, 1e-37, 1e-36,
1e-35, 1e-34, 1e-33, 1e-32, 1e-31, 1e-30, 1e-29, 1e-28, 1e-27, 1e-26, 1e-25, 1e-24, 1e-23,
1e-22, 1e-21, 1e-20, 1e-19, 1e-18, 1e-17, 1e-16, 1e-15, 1e-14, 1e-13, 1e-12, 1e-11, 1e-10,
1e-9, 1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6,
1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22,
1e23, 1e24, 1e25, 1e26, 1e27, 1e28, 1e29, 1e30, 1e31, 1e32, 1e33, 1e34, 1e35, 1e36, 1e37,
1e38, 1e39, 1e40, 1e41, 1e42, 1e43, 1e44, 1e45, 1e46, 1e47, 1e48, 1e49, 1e50, 1e51, 1e52,
1e53, 1e54, 1e55, 1e56, 1e57, 1e58, 1e59, 1e60, 1e61, 1e62, 1e63, 1e64, 1e65, 1e66, 1e67,
1e68, 1e69, 1e70, 1e71, 1e72, 1e73, 1e74, 1e75, 1e76, 1e77, 1e78, 1e79, 1e80, 1e81, 1e82,
1e83, 1e84, 1e85, 1e86, 1e87, 1e88, 1e89, 1e90, 1e91, 1e92, 1e93, 1e94, 1e95, 1e96, 1e97,
1e98, 1e99, 1e100
};
double ipow10_table[601];
unsigned stou(const char *s, void *endptr, unsigned base)
{
@ -166,77 +150,59 @@ int64 ScanInt64(const char *ptr)
return ScanInt<char, byte, uint64, int64, 10>(x, ptr, overflow) && !overflow ? x : Null;
}
template <class T>
double ScanDoubleT(const T *p, const T **endptr, bool accept_comma)
double ScanDouble(const char *ptr, const char **endptr, bool accept_comma)
{
const T *begin = p;
while(*p && (byte)*p <= ' ')
p++;
bool neg = false;
if(endptr)
*endptr = p;
if(*p == '+' || *p == '-')
neg = (*p++ == '-');
if((byte)(*p - '0') >= 10 && !((*p == '.' || accept_comma && *p == ',') && (byte)(p[1] - '0') < 10)) {
if(endptr) *endptr = begin;
return Null;
}
double mantissa = 0;
T c;
int exp = 0;
while((byte)(*p - '0') < 10)
if((c = *p++) != '0') {
if(exp) { mantissa *= ipow10(exp); exp = 0; }
mantissa = 10 * mantissa + c - '0';
}
else
exp++;
int raise = exp;
if(*p == '.' || accept_comma && *p == ',') // decimal part
while((byte)((c = *++p) - '0') < 10) {
if(c != '0') {
if(raise) {
mantissa *= ipow10(raise);
exp -= raise;
raise = 0;
}
exp--;
mantissa = 10 * mantissa + c - '0';
if(!IsFin(mantissa))
return Null;
}
else
raise++;
}
if(*p == 'E' || *p == 'e') { // exponent
int vexp = ScanInt(p + 1, &p);
if(IsNull(vexp))
return Null;
exp += vexp;
}
if(endptr) *endptr = p;
if(exp) {
double e = ipow10(tabs(exp));
mantissa = (exp > 0 ? mantissa * e : mantissa / e);
}
if(!IsFin(mantissa))
return Null;
return neg ? -mantissa : mantissa;
double n;
ptr = ScanDbl<char, byte>(n, ptr, accept_comma ? ',' : '.');
if(ptr && endptr)
*endptr = ptr;
return ptr ? n : Null;
}
double ScanDouble(const char *p, const char **endptr, bool accept_comma)
double ScanDouble(const wchar *ptr, const wchar **endptr, bool accept_comma)
{
return ScanDoubleT(p, endptr, accept_comma);
double n;
ptr = ScanDbl<wchar, word>(n, ptr, accept_comma ? ',' : '.');
if(ptr && endptr)
*endptr = ptr;
return ptr ? n : Null;
}
double ScanDouble(const wchar *p, const wchar **endptr, bool accept_comma)
double ScanDouble(const char *ptr, const char **endptr)
{
return ScanDoubleT(p, endptr, accept_comma);
double n;
ptr = ScanDbl<char, byte>(n, ptr, ',');
if(ptr && endptr)
*endptr = ptr;
return ptr ? n : Null;
}
double ScanDouble(const wchar *ptr, const wchar **endptr)
{
double n;
ptr = ScanDbl<wchar, word>(n, ptr, ',');
if(ptr && endptr)
*endptr = ptr;
return ptr ? n : Null;
}
double ScanDouble(const char *ptr)
{
double n;
ptr = ScanDbl<char, byte>(n, ptr, ',');
return ptr ? n : Null;
}
double ScanDouble(const wchar *ptr)
{
double n;
return ScanDbl<wchar, word>(n, ptr, ',') ? n : Null;
}
double Atof(const char *s)
{
return Nvl(ScanDouble(s));
double n;
return ScanDbl<char, byte>(n, s, ',') ? n : 0;
}
Value StrIntValue(const char *s)

View file

@ -17,8 +17,12 @@ int64 ScanInt64(const char *ptr, const char **endptr, int radix);
int64 ScanInt64(const char *ptr, const char **endptr);
int64 ScanInt64(const char *ptr);
double ScanDouble(const char *ptr, const char **endptr = NULL, bool accept_comma = true);
double ScanDouble(const wchar *ptr, const wchar **endptr = NULL, bool accept_comma = true);
double ScanDouble(const char *ptr, const char **endptr, bool accept_comma);
double ScanDouble(const wchar *ptr, const wchar **endptr, bool accept_comma);
double ScanDouble(const char *ptr, const char **endptr);
double ScanDouble(const wchar *ptr, const wchar **endptr);
double ScanDouble(const char *ptr);
double ScanDouble(const wchar *ptr);
double Atof(const char *s);

View file

@ -177,12 +177,16 @@ const CHAR *ScanDbl(double& result, const CHAR *s, int alt_dp = '.')
};
#endif
double number = (double)ReadNumber();
extern double ipow10_table[601];
auto pow10i = [](double i) {
extern double ipow10_table[];
if(i >= -100 && i <= 100)
return ipow10_table[(int)i + 100];
if(i >= -300 && i <= 300)
return ipow10_table[(int)i + 300];
return pow(10.0, i);
};
ONCELOCK {
for(int i = -300; i <= 300; i++)
ipow10_table[i + 300] = pow(10.0, i);
}
if(*s == '.' || *s == alt_dp) {
s++;
int dp = 0;

View file

@ -386,25 +386,13 @@ bool CParser::IsDouble2() const
double CParser::ReadDouble()
{
LTIMING("ReadDouble");
int sign = Sgn();
if(!IsDigit(*term) && *term != '.')
ThrowError("missing number");
double n = 0;
while(IsDigit(*term))
n = 10 * n + *term++ - '0';
if(Char('.')) {
double q = 1;
while(IsDigit(*term)) {
q = 0.1 * q;
n += q * (*term++ - '0');
}
}
if(Char('e') || Char('E'))
n *= pow(10.0, ReadInt());
DoSpaces();
n = sign * n;
double n;
const char *t = ScanDbl<char, byte>(n, term, '.');
if(!t) ThrowError("missing number");
if(!IsFin(n))
ThrowError("number is too big");
term = t;
DoSpaces();
return n;
}