From 11a2c6f2147dd90d233bc6ed687f9787e99f045d Mon Sep 17 00:00:00 2001 From: cxl Date: Tue, 22 Jun 2021 11:33:39 +0000 Subject: [PATCH] Core: text->double conversion refactored / optimised git-svn-id: svn://ultimatepp.org/upp/trunk@16002 f0d560ea-af0d-0410-9eb7-867de7ffcac7 --- uppsrc/Core/Convert.cpp | 120 ++++++++++++++-------------------------- uppsrc/Core/Convert.h | 8 ++- uppsrc/Core/Convert.hpp | 10 +++- uppsrc/Core/parser.cpp | 22 ++------ 4 files changed, 61 insertions(+), 99 deletions(-) diff --git a/uppsrc/Core/Convert.cpp b/uppsrc/Core/Convert.cpp index 47460db69..cbbff7e0f 100644 --- a/uppsrc/Core/Convert.cpp +++ b/uppsrc/Core/Convert.cpp @@ -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(x, ptr, overflow) && !overflow ? x : Null; } -template -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(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(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(n, ptr, ','); + if(ptr && endptr) + *endptr = ptr; + return ptr ? n : Null; +} + +double ScanDouble(const wchar *ptr, const wchar **endptr) +{ + double n; + ptr = ScanDbl(n, ptr, ','); + if(ptr && endptr) + *endptr = ptr; + return ptr ? n : Null; +} + +double ScanDouble(const char *ptr) +{ + double n; + ptr = ScanDbl(n, ptr, ','); + return ptr ? n : Null; +} + +double ScanDouble(const wchar *ptr) +{ + double n; + return ScanDbl(n, ptr, ',') ? n : Null; } double Atof(const char *s) { - return Nvl(ScanDouble(s)); + double n; + return ScanDbl(n, s, ',') ? n : 0; } Value StrIntValue(const char *s) diff --git a/uppsrc/Core/Convert.h b/uppsrc/Core/Convert.h index fdebc5720..afdcb1e68 100644 --- a/uppsrc/Core/Convert.h +++ b/uppsrc/Core/Convert.h @@ -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); diff --git a/uppsrc/Core/Convert.hpp b/uppsrc/Core/Convert.hpp index 8e3ef14d4..b93eb5410 100644 --- a/uppsrc/Core/Convert.hpp +++ b/uppsrc/Core/Convert.hpp @@ -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; diff --git a/uppsrc/Core/parser.cpp b/uppsrc/Core/parser.cpp index cedd7698e..dfef7db57 100644 --- a/uppsrc/Core/parser.cpp +++ b/uppsrc/Core/parser.cpp @@ -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(n, term, '.'); + if(!t) ThrowError("missing number"); if(!IsFin(n)) ThrowError("number is too big"); + term = t; + DoSpaces(); return n; }