PIString::toFloat/Double/LDouble own fast implementation (. and , equivalent)

PICout ldouble support
PIEthernet small optimization
This commit is contained in:
2022-09-17 17:53:58 +03:00
parent eddef26b5e
commit 499ee386a7
8 changed files with 270 additions and 103 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 1) set(PIP_MINOR 1)
set(PIP_REVISION 1) set(PIP_REVISION 2)
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

@@ -392,6 +392,8 @@ PICout & PICout::operator <<(float v) {if (!act_) return *this; space(); PIFLOAT
PICout & PICout::operator <<(double v) {if (!act_) return *this; space(); PIFLOATCOUT(v)} PICout & PICout::operator <<(double v) {if (!act_) return *this; space(); PIFLOATCOUT(v)}
PICout & PICout::operator <<(ldouble v) {if (!act_) return *this; space(); PIFLOATCOUT(v)}
PICout & PICout::operator <<(const void * v) { PICout & PICout::operator <<(const void * v) {
if (!act_) return *this; if (!act_) return *this;
space(); space();

View File

@@ -230,6 +230,10 @@ public:
//! \~russian Оператор вывода для <tt>"double"</tt> значений //! \~russian Оператор вывода для <tt>"double"</tt> значений
PICout & operator <<(double v); PICout & operator <<(double v);
//! \~english Output operator for <tt>"ldouble"</tt> values
//! \~russian Оператор вывода для <tt>"ldouble"</tt> значений
PICout & operator <<(ldouble v);
//! \~english Output operator for pointers //! \~english Output operator for pointers
//! \~russian Оператор вывода для указателей //! \~russian Оператор вывода для указателей
PICout & operator <<(const void * v); PICout & operator <<(const void * v);

View File

@@ -20,6 +20,7 @@
#include "piincludes_p.h" #include "piincludes_p.h"
#include "pistring.h" #include "pistring.h"
#include "pistringlist.h" #include "pistringlist.h"
#include "pimathbase.h"
#ifdef PIP_ICU #ifdef PIP_ICU
# define U_NOEXCEPT # define U_NOEXCEPT
# include "unicode/ucnv.h" # include "unicode/ucnv.h"
@@ -78,6 +79,97 @@ 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>
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.;
for (const PIChar pc: s) {
char c = pc.toAscii();
switch (part) {
case 0: // sign
if (pc.isSpace()) continue;
if (c >= '0' && c <= '9') {
ret = c - '0';
part = 1;
continue;
}
if (c == '+') {
part = 1;
continue;
}
if (c == '-') {
negative = true;
part = 1;
continue;
}
if (c == '.' || c == ',') {
part = 2;
continue;
}
err = true;
break;
case 1: // integer
if (c >= '0' && c <= '9') {
ret = ret * 10 + (c - '0');
continue;
}
if (c == '.' || c == ',') {
part = 2;
continue;
}
if (c == 'e' || c == 'E') {
part = 3;
continue;
}
err = true;
break;
case 2: // fractional
if (c >= '0' && c <= '9') {
frac += (c - '0') / frac_delim;
frac_delim *= 10;
continue;
}
if (c == 'e' || c == 'E') {
part = 3;
continue;
}
err = true;
break;
case 3: // exponent with sign
if (c == '+') {
part = 4;
continue;
}
if (c == '-') {
negative_exp = true;
part = 4;
continue;
}
case 4: // exponent
if (c >= '0' && c <= '9') {
exp = (exp * 10) + (c - '0');
continue;
}
err = true;
break;
}
if (err) break;
}
ret += frac;
if (negative) ret = -ret;
if (exp > 0) {
if (negative_exp) ret /= pow10((T)exp);
else ret *= pow10((T)exp);
}
return ret;
}
#define pisprintf(f, v) char ch[256]; memset(ch, 0, 256); snprintf(ch, 256, f, v); return PIStringAscii(ch); #define pisprintf(f, v) char ch[256]; memset(ch, 0, 256); snprintf(ch, 256, f, v); return PIStringAscii(ch);
PIString PIString::itos(const int num) {pisprintf("%d", num);} PIString PIString::itos(const int num) {pisprintf("%d", num);}
@@ -1023,7 +1115,7 @@ bool PIString::toBool() const {
PIString s(*this); PIString s(*this);
s = s.trimmed().toLowerCase(); s = s.trimmed().toLowerCase();
if (s == s_true || s == s_yes || s == s_on || s == s_ok) return true; if (s == s_true || s == s_yes || s == s_on || s == s_ok) return true;
if (atof(s.toNativeDecimalPoints().data()) > 0.) return true; if (toDouble() > 0.) return true;
return false; return false;
} }
@@ -1432,37 +1524,25 @@ PIString PIString::toLowerCase() const {
} }
PIString PIString::toNativeDecimalPoints() const {
#ifdef HAS_LOCALE
PIString s(*this);
if (currentLocale == 0) return s;
return s.replaceAll('.', currentLocale->decimal_point).replaceAll(',', currentLocale->decimal_point);
#else
return PIString(*this).replaceAll(',', '.');
#endif
}
char PIString::toChar() const { char PIString::toChar() const {
PIString s(toNativeDecimalPoints());
char v; char v;
sscanf(s.data(), "%c", &v); sscanf(dataAscii(), "%c", &v);
return v; return v;
} }
float PIString::toFloat() const { float PIString::toFloat() const {
return (float)atof(toNativeDecimalPoints().data()); return toDecimal<float>(*this);
} }
double PIString::toDouble() const { double PIString::toDouble() const {
return atof(toNativeDecimalPoints().data()); return toDecimal<double>(*this);
} }
ldouble PIString::toLDouble() const { ldouble PIString::toLDouble() const {
return atof(toNativeDecimalPoints().data()); return toDecimal<ldouble>(*this);
} }

View File

@@ -870,9 +870,6 @@ public:
//! \~russian Преобразует каждый символ в скопированной строке в нижний регистр. //! \~russian Преобразует каждый символ в скопированной строке в нижний регистр.
PIString toLowerCase() const; PIString toLowerCase() const;
// TODO: doxygen
PIString toNativeDecimalPoints() const;
//! \~english Returns if string contains character "c". //! \~english Returns if string contains character "c".
//! \~russian Возвращает содержит ли строка символ "c". //! \~russian Возвращает содержит ли строка символ "c".

View File

@@ -909,6 +909,17 @@ void PIEthernet::server_func(void * eth) {
} }
void PIEthernet::setType(Type t, bool reopen) {
eth_type = t;
setProperty("type", (int)t);
if (reopen && isOpened()) {
closeDevice();
init();
openDevice();
}
}
bool PIEthernet::configureDevice(const void * e_main, const void * e_parent) { bool PIEthernet::configureDevice(const void * e_main, const void * e_parent) {
PIConfig::Entry * em = (PIConfig::Entry * )e_main; PIConfig::Entry * em = (PIConfig::Entry * )e_main;
PIConfig::Entry * ep = (PIConfig::Entry * )e_parent; PIConfig::Entry * ep = (PIConfig::Entry * )e_parent;

View File

@@ -213,7 +213,7 @@ public:
PIFlags<PIEthernet::Parameters> parameters() const {return (PIFlags<PIEthernet::Parameters>)(property("parameters").toInt());} PIFlags<PIEthernet::Parameters> parameters() const {return (PIFlags<PIEthernet::Parameters>)(property("parameters").toInt());}
//! Returns %PIEthernet type //! Returns %PIEthernet type
Type type() const {return (Type)(property("type").toInt());} Type type() const {return eth_type;}
//! Returns read timeout //! Returns read timeout
double readTimeout() const {return property("readTimeout").toDouble();} double readTimeout() const {return property("readTimeout").toDouble();}
@@ -489,6 +489,7 @@ protected:
int sock, sock_s; int sock, sock_s;
bool connected_, connecting_, listen_threaded, server_bounded; bool connected_, connecting_, listen_threaded, server_bounded;
mutable Address addr_r, addr_s, addr_lr; mutable Address addr_r, addr_s, addr_lr;
Type eth_type;
PIThread server_thread_; PIThread server_thread_;
PIMutex clients_mutex; PIMutex clients_mutex;
PIVector<PIEthernet * > clients_; PIVector<PIEthernet * > clients_;
@@ -498,7 +499,7 @@ protected:
private: private:
EVENT_HANDLER1(void, clientDeleted, PIObject *, o); EVENT_HANDLER1(void, clientDeleted, PIObject *, o);
static void server_func(void * eth); static void server_func(void * eth);
void setType(Type t, bool reopen = true) {setProperty("type", (int)t); if (reopen && isOpened()) {closeDevice(); init(); openDevice();}} void setType(Type t, bool reopen = true);
static int ethErrorCore(); static int ethErrorCore();
static PIString ethErrorString(); static PIString ethErrorString();

232
main.cpp
View File

@@ -1,97 +1,169 @@
#include "pip.h" #include "pip.h"
#include "piiostream.h" #include "piiostream.h"
#include "pibytearray.h" #include "pibytearray.h"
#include <vector> #include "pimathbase.h"
#include <list>
using namespace PICoutManipulators; using namespace PICoutManipulators;
#define SZ 256 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);}
class A { template <typename T>
public: T toDouble(const PIString & s) {
A() : id_(666) { int part = 0;
arr = new int[SZ]; bool negative = false, negative_exp = false, err = false;
piCout << "def A()" << id_ << this << arr; T ret = 0., frac = 0., frac_delim = 10., exp = 0;
} for (const PIChar pc: s) {
A(int id) : id_(id) { char c = pc.toAscii();
arr = new int[SZ]; switch (part) {
piCout << "A(int)" << id_ << this << arr; case 0: // sign
} if (pc.isSpace()) continue;
if (c >= '0' && c <= '9') {
A(const A & a) { ret = c - '0';
arr = new int[SZ]; part = 1;
id_ = a.id_; continue;
piCout << "A(A)" << id_ << this << arr; }
} if (c == '+') {
part = 1;
A(A && a) { continue;
std::swap(id_, a.id_); }
std::swap(arr, a.arr); if (c == '-') {
piCout << "move A(A)" << id_ << this << arr; negative = true;
} part = 1;
continue;
~A() { }
if (arr) { if (c == '.' || c == ',') {
memset(arr, 0, SZ * 4); part = 2;
delete arr; continue;
}
err = true;
break;
case 1: // integer
if (c >= '0' && c <= '9') {
ret = ret * 10 + (c - '0');
continue;
}
if (c == '.' || c == ',') {
part = 2;
continue;
}
if (c == 'e' || c == 'E') {
part = 3;
continue;
}
err = true;
break;
case 2: // fractional
if (c >= '0' && c <= '9') {
frac += (c - '0') / frac_delim;
frac_delim *= 10;
continue;
}
if (c == 'e' || c == 'E') {
part = 3;
continue;
}
err = true;
break;
case 3: // exponent with sign
if (c == '+') {
part = 4;
continue;
}
if (c == '-') {
negative_exp = true;
part = 4;
continue;
}
case 4: // exponent
if (c >= '0' && c <= '9') {
exp = (exp * 10) + (c - '0');
continue;
}
err = true;
break;
} }
piCout << "~A()" << id_ << this << arr; if (err) break;
//id_ = 0;
} }
ret += frac;
inline A & operator =(const A & a) { if (negative) ret = -ret;
id_ = a.id_; if (exp > 0) {
piCout << "A =" << id_ << this; if (negative_exp) ret /= pow10(exp);
return *this; else ret *= pow10(exp);
} }
return ret;
}
inline A & operator =(A && a) { inline void test(const PIString & s) {
std::swap(id_, a.id_); double av = toDouble<double>(s);
std::swap(arr, a.arr); double v = s.toDouble();
piCout << "move A=" << id_ << this; piCout << s << "=" << v << av;
return *this; }
}
private:
int id_ = -1;
int * arr = 0;
};
//class B {
//public:
// B() {a_ = nullptr;}
// ~B() {if (a_) delete a_;}
// void setA(A && a) {
// a_ = (A *)malloc(sizeof(a));
// memcpy(a_, &a, sizeof(a));
// operator delete(&a);
// }
// void setA(const A & a) {a_ = new A(a);}
//private:
// A * a_;
//};
int main(int argc, char * argv[]) { int main(int argc, char * argv[]) {
piCout << "pip 3.1"; /*test(" 123 ");
{ test("\n123 ");
PIDeque<A> v; test("\t123 ");
//A a; test(" +123 ");
//v.push_back(a); test(" ++123 ");
//v.push_back(std::move(a)); test(" + 123 ");
v.push_back(A(1)); test(" -123 ");
v.push_back(A(2)); test(" --123 ");
v.push_back(A(3)); test(" - 123 ");
} test("123.1");
test("123 .1");
test("123 . 1");
test("123.+1");
test("123.-1");
test("123E2");
test("123E+2");
test("123E +2");
test("123E+ 2");
test("123E + 2");
test("123 E+2");
test("123 E +2");
test("123 E+ 2");
test("123 E + 2");
test("123E+2.5");
test("123.4E+2");
test("123.4.5E+2");
test("123EE+2");
test("123e+2");
test("123e++2");
test("E+2");
test("1E+2");
test("1.E+2");
test(".E+2");
test(".1E-2");
test("+E2");
test("nan");
test("inf");*/
test("1.23");
test("1,23");
test(".23");
test(",23");
PITimeMeasurer tm;
PIString s("1E+600");
int cnt = 1000000;
int el_o = 0, el_n = 0;
ldouble v = 0.;
NO_UNUSED(v);
piCout << ""; tm.reset();
piCout << "std"; piForTimes (cnt) {
{ v = s.toLDouble();
std::vector<A> v;
v.push_back(A(1));
v.push_back(A(2));
v.push_back(A(3));
} }
el_o = tm.elapsed_u();
piCout << v << el_o;
tm.reset();
piForTimes (cnt) {
v = toDouble<ldouble>(s);
}
el_n = tm.elapsed_u();
piCout << v << el_n;
piCout << (double)el_o / el_n;
return 0; return 0;
} }