pistring::toFloat/Double/LDouble precise fixes

This commit is contained in:
2022-09-19 15:20:24 +03:00
parent 38840c5b7d
commit 858b54ce64
4 changed files with 53 additions and 38 deletions

View File

@@ -3,7 +3,7 @@ cmake_policy(SET CMP0017 NEW) # need include() with .cmake
project(PIP) project(PIP)
set(PIP_MAJOR 3) set(PIP_MAJOR 3)
set(PIP_MINOR 2) set(PIP_MINOR 2)
set(PIP_REVISION 0) set(PIP_REVISION 1)
set(PIP_SUFFIX ) set(PIP_SUFFIX )
set(PIP_COMPANY SHS) set(PIP_COMPANY SHS)
set(PIP_DOMAIN org.SHS) set(PIP_DOMAIN org.SHS)

View File

@@ -79,21 +79,18 @@ const float PIString::ElideCenter = .5f;
const float PIString::ElideRight = 1.f; 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 <typename T> template <typename T>
T toDecimal(const PIString & s) { T toDecimal(const PIString & s) {
int part = 0, exp = 0; int part = 0, exp = 0;
bool negative = false, negative_exp = false, err = false; bool negative = false, negative_exp = false, err = false, has_digit = false;
T ret = 0., frac = 0., frac_delim = 10.; T ret = 0., frac = 0., frac_delim = 1.;
for (const PIChar pc: s) { for (const PIChar pc: s) {
char c = pc.toAscii(); char c = pc.toAscii();
switch (part) { switch (part) {
case 0: // sign case 0: // sign
if (pc.isSpace()) continue; if (pc.isSpace()) continue;
if (c >= '0' && c <= '9') { if (c >= '0' && c <= '9') {
has_digit = true;
ret = c - '0'; ret = c - '0';
part = 1; part = 1;
continue; continue;
@@ -115,6 +112,7 @@ T toDecimal(const PIString & s) {
break; break;
case 1: // integer case 1: // integer
if (c >= '0' && c <= '9') { if (c >= '0' && c <= '9') {
has_digit = true;
ret = ret * 10 + (c - '0'); ret = ret * 10 + (c - '0');
continue; continue;
} }
@@ -122,7 +120,7 @@ T toDecimal(const PIString & s) {
part = 2; part = 2;
continue; continue;
} }
if (c == 'e' || c == 'E') { if ((c == 'e' || c == 'E') && has_digit) {
part = 3; part = 3;
continue; continue;
} }
@@ -130,11 +128,12 @@ T toDecimal(const PIString & s) {
break; break;
case 2: // fractional case 2: // fractional
if (c >= '0' && c <= '9') { if (c >= '0' && c <= '9') {
frac += (c - '0') / frac_delim; has_digit = true;
frac_delim *= 10; frac = frac * 10 + (c - '0');
frac_delim *= 10.;
continue; continue;
} }
if (c == 'e' || c == 'E') { if ((c == 'e' || c == 'E') && has_digit) {
part = 3; part = 3;
continue; continue;
} }
@@ -160,8 +159,9 @@ T toDecimal(const PIString & s) {
} }
if (err) break; if (err) break;
} }
frac /= frac_delim;
ret += frac; ret += frac;
if (negative) ret = -ret; if (negative && has_digit) ret = -ret;
if (exp > 0) { if (exp > 0) {
if (negative_exp) ret /= pow10((T)exp); if (negative_exp) ret /= pow10((T)exp);
else ret *= pow10((T)exp); else ret *= pow10((T)exp);

View File

@@ -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 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 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 sign(const ldouble & x) {return (x < 0.L) ? -1 : (x > 0.L ? 1 : 0);}
inline int pow2(const int p) {return 1 << p;} 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;} 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); PIP_EXPORT double piJ0(const double & v);

View File

@@ -5,21 +5,18 @@
using namespace PICoutManipulators; 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 <typename T> template <typename T>
T toDouble(const PIString & s) { T toDecimal(const PIString & s) {
int part = 0; int part = 0, exp = 0;
bool negative = false, negative_exp = false, err = false; bool negative = false, negative_exp = false, err = false, has_digit = false;
T ret = 0., frac = 0., frac_delim = 10., exp = 0; T ret = 0., frac = 0., frac_delim = 1.;
for (const PIChar pc: s) { for (const PIChar pc: s) {
char c = pc.toAscii(); char c = pc.toAscii();
switch (part) { switch (part) {
case 0: // sign case 0: // sign
if (pc.isSpace()) continue; if (pc.isSpace()) continue;
if (c >= '0' && c <= '9') { if (c >= '0' && c <= '9') {
has_digit = true;
ret = c - '0'; ret = c - '0';
part = 1; part = 1;
continue; continue;
@@ -41,6 +38,7 @@ T toDouble(const PIString & s) {
break; break;
case 1: // integer case 1: // integer
if (c >= '0' && c <= '9') { if (c >= '0' && c <= '9') {
has_digit = true;
ret = ret * 10 + (c - '0'); ret = ret * 10 + (c - '0');
continue; continue;
} }
@@ -48,7 +46,7 @@ T toDouble(const PIString & s) {
part = 2; part = 2;
continue; continue;
} }
if (c == 'e' || c == 'E') { if ((c == 'e' || c == 'E') && has_digit) {
part = 3; part = 3;
continue; continue;
} }
@@ -56,11 +54,14 @@ T toDouble(const PIString & s) {
break; break;
case 2: // fractional case 2: // fractional
if (c >= '0' && c <= '9') { if (c >= '0' && c <= '9') {
frac += (c - '0') / frac_delim; has_digit = true;
frac_delim *= 10; frac = frac * 10 + (c - '0');
frac_delim *= 10.;
//piCout << frac << frac_delim;
//printf("%.20f %.20f\n", frac, T(c - '0') / frac_delim);
continue; continue;
} }
if (c == 'e' || c == 'E') { if ((c == 'e' || c == 'E') && has_digit) {
part = 3; part = 3;
continue; continue;
} }
@@ -86,19 +87,23 @@ T toDouble(const PIString & s) {
} }
if (err) break; if (err) break;
} }
frac /= frac_delim;
ret += frac; ret += frac;
if (negative) ret = -ret; if (negative && has_digit) ret = -ret;
if (exp > 0) { if (exp > 0) {
if (negative_exp) ret /= pow10(exp); if (negative_exp) ret /= pow10((T)exp);
else ret *= pow10(exp); else ret *= pow10((T)exp);
} }
return ret; return ret;
} }
inline void test(const PIString & s) { inline void test(const PIString & s) {
double av = toDouble<double>(s); double av = atof(s.dataAscii());
double v = s.toDouble(); double v = toDecimal<double>(s);
printf("\n");
piCout << s << "=" << v << av; piCout << s << "=" << v << av;
printf("atof = %.20f\n", av);
printf(" PIP = %.20f\n", v);
} }
int main(int argc, char * argv[]) { int main(int argc, char * argv[]) {
@@ -139,27 +144,32 @@ int main(int argc, char * argv[]) {
test("+E2"); test("+E2");
test("nan"); test("nan");
test("inf");*/ test("inf");*/
test("1.23"); test("-");
test("1,23"); test("-0");
test(".23"); test("-.");
test(",23"); test("-.0");
test(".23456123456789987654");
test("-E+100");
return 0;
PITimeMeasurer tm; PITimeMeasurer tm;
PIString s("1E+600"); PIString s("1.23456789");
int cnt = 1000000; int cnt = 10000000;
int el_o = 0, el_n = 0; int el_o = 0, el_n = 0;
ldouble v = 0.; double v = 0.;
NO_UNUSED(v); NO_UNUSED(v);
tm.reset(); tm.reset();
piForTimes (cnt) { piForTimes (cnt) {
v = s.toLDouble(); v = s.toDouble();
} }
el_o = tm.elapsed_u(); el_o = tm.elapsed_u();
piCout << v << el_o; piCout << v << el_o;
tm.reset(); tm.reset();
piForTimes (cnt) { piForTimes (cnt) {
v = toDouble<ldouble>(s); v = toDecimal<double>(s);
} }
el_n = tm.elapsed_u(); el_n = tm.elapsed_u();
piCout << v << el_n; piCout << v << el_n;