From 858b54ce64c1f490354c829d6cc8852409eb2386 Mon Sep 17 00:00:00 2001 From: peri4 Date: Mon, 19 Sep 2022 15:20:24 +0300 Subject: [PATCH] pistring::toFloat/Double/LDouble precise fixes --- CMakeLists.txt | 2 +- libs/main/core/pistring.cpp | 22 ++++++------- libs/main/math/pimathbase.h | 5 +++ main.cpp | 62 +++++++++++++++++++++---------------- 4 files changed, 53 insertions(+), 38 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3b443286..f14ac82a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_policy(SET CMP0017 NEW) # need include() with .cmake project(PIP) set(PIP_MAJOR 3) set(PIP_MINOR 2) -set(PIP_REVISION 0) +set(PIP_REVISION 1) set(PIP_SUFFIX ) set(PIP_COMPANY SHS) set(PIP_DOMAIN org.SHS) diff --git a/libs/main/core/pistring.cpp b/libs/main/core/pistring.cpp index 1b162921..2c041a64 100644 --- a/libs/main/core/pistring.cpp +++ b/libs/main/core/pistring.cpp @@ -79,21 +79,18 @@ const float PIString::ElideCenter = .5f; const float PIString::ElideRight = 1.f; -inline float pow10(const int & e) {return powf(10.f, e);} -inline double pow10(const double & e) {return pow(10., e);} -inline ldouble pow10(const ldouble & e) {return powl(10.L, e);} - template T toDecimal(const PIString & s) { int part = 0, exp = 0; - bool negative = false, negative_exp = false, err = false; - T ret = 0., frac = 0., frac_delim = 10.; + bool negative = false, negative_exp = false, err = false, has_digit = false; + T ret = 0., frac = 0., frac_delim = 1.; for (const PIChar pc: s) { char c = pc.toAscii(); switch (part) { case 0: // sign if (pc.isSpace()) continue; if (c >= '0' && c <= '9') { + has_digit = true; ret = c - '0'; part = 1; continue; @@ -115,6 +112,7 @@ T toDecimal(const PIString & s) { break; case 1: // integer if (c >= '0' && c <= '9') { + has_digit = true; ret = ret * 10 + (c - '0'); continue; } @@ -122,7 +120,7 @@ T toDecimal(const PIString & s) { part = 2; continue; } - if (c == 'e' || c == 'E') { + if ((c == 'e' || c == 'E') && has_digit) { part = 3; continue; } @@ -130,11 +128,12 @@ T toDecimal(const PIString & s) { break; case 2: // fractional if (c >= '0' && c <= '9') { - frac += (c - '0') / frac_delim; - frac_delim *= 10; + has_digit = true; + frac = frac * 10 + (c - '0'); + frac_delim *= 10.; continue; } - if (c == 'e' || c == 'E') { + if ((c == 'e' || c == 'E') && has_digit) { part = 3; continue; } @@ -160,8 +159,9 @@ T toDecimal(const PIString & s) { } if (err) break; } + frac /= frac_delim; ret += frac; - if (negative) ret = -ret; + if (negative && has_digit) ret = -ret; if (exp > 0) { if (negative_exp) ret /= pow10((T)exp); else ret *= pow10((T)exp); diff --git a/libs/main/math/pimathbase.h b/libs/main/math/pimathbase.h index 3cd698c2..866fec42 100644 --- a/libs/main/math/pimathbase.h +++ b/libs/main/math/pimathbase.h @@ -101,7 +101,12 @@ const double rad2deg = M_180_PI; inline int sign(const float & x) {return (x < 0.f) ? -1 : (x > 0.f ? 1 : 0);} inline int sign(const double & x) {return (x < 0. ) ? -1 : (x > 0. ? 1 : 0);} inline int sign(const ldouble & x) {return (x < 0.L) ? -1 : (x > 0.L ? 1 : 0);} + inline int pow2(const int p) {return 1 << p;} +inline float pow10(const int & e) {return powf(10.f, e);} +inline double pow10(const double & e) {return pow(10., e);} +inline ldouble pow10(const ldouble & e) {return powl(10.L, e);} + inline double sinc(const double & v) {if (v == 0.) return 1.; double t = M_PI * v; return sin(t) / t;} PIP_EXPORT double piJ0(const double & v); diff --git a/main.cpp b/main.cpp index abbe7ab4..22dad5b9 100644 --- a/main.cpp +++ b/main.cpp @@ -5,21 +5,18 @@ using namespace PICoutManipulators; -inline float pow10(const int & e) {return powf(10.f, e);} -inline double pow10(const double & e) {return pow(10., e);} -inline ldouble pow10(const ldouble & e) {return powl(10.L, e);} - template -T toDouble(const PIString & s) { - int part = 0; - bool negative = false, negative_exp = false, err = false; - T ret = 0., frac = 0., frac_delim = 10., exp = 0; +T toDecimal(const PIString & s) { + int part = 0, exp = 0; + bool negative = false, negative_exp = false, err = false, has_digit = false; + T ret = 0., frac = 0., frac_delim = 1.; for (const PIChar pc: s) { char c = pc.toAscii(); switch (part) { case 0: // sign if (pc.isSpace()) continue; if (c >= '0' && c <= '9') { + has_digit = true; ret = c - '0'; part = 1; continue; @@ -41,6 +38,7 @@ T toDouble(const PIString & s) { break; case 1: // integer if (c >= '0' && c <= '9') { + has_digit = true; ret = ret * 10 + (c - '0'); continue; } @@ -48,7 +46,7 @@ T toDouble(const PIString & s) { part = 2; continue; } - if (c == 'e' || c == 'E') { + if ((c == 'e' || c == 'E') && has_digit) { part = 3; continue; } @@ -56,11 +54,14 @@ T toDouble(const PIString & s) { break; case 2: // fractional if (c >= '0' && c <= '9') { - frac += (c - '0') / frac_delim; - frac_delim *= 10; + has_digit = true; + frac = frac * 10 + (c - '0'); + frac_delim *= 10.; + //piCout << frac << frac_delim; + //printf("%.20f %.20f\n", frac, T(c - '0') / frac_delim); continue; } - if (c == 'e' || c == 'E') { + if ((c == 'e' || c == 'E') && has_digit) { part = 3; continue; } @@ -86,19 +87,23 @@ T toDouble(const PIString & s) { } if (err) break; } + frac /= frac_delim; ret += frac; - if (negative) ret = -ret; + if (negative && has_digit) ret = -ret; if (exp > 0) { - if (negative_exp) ret /= pow10(exp); - else ret *= pow10(exp); + if (negative_exp) ret /= pow10((T)exp); + else ret *= pow10((T)exp); } return ret; } inline void test(const PIString & s) { - double av = toDouble(s); - double v = s.toDouble(); + double av = atof(s.dataAscii()); + double v = toDecimal(s); + printf("\n"); piCout << s << "=" << v << av; + printf("atof = %.20f\n", av); + printf(" PIP = %.20f\n", v); } int main(int argc, char * argv[]) { @@ -139,27 +144,32 @@ int main(int argc, char * argv[]) { test("+E2"); test("nan"); test("inf");*/ - test("1.23"); - test("1,23"); - test(".23"); - test(",23"); + test("-"); + test("-0"); + test("-."); + test("-.0"); + test(".23456123456789987654"); + test("-E+100"); + + return 0; + PITimeMeasurer tm; - PIString s("1E+600"); - int cnt = 1000000; + PIString s("1.23456789"); + int cnt = 10000000; int el_o = 0, el_n = 0; - ldouble v = 0.; + double v = 0.; NO_UNUSED(v); tm.reset(); piForTimes (cnt) { - v = s.toLDouble(); + v = s.toDouble(); } el_o = tm.elapsed_u(); piCout << v << el_o; tm.reset(); piForTimes (cnt) { - v = toDouble(s); + v = toDecimal(s); } el_n = tm.elapsed_u(); piCout << v << el_n;