Skip to content

Commit

Permalink
Use exception only in convert() functions
Browse files Browse the repository at this point in the history
I changed the code in private convertTo* functions to the original
form (return bool). This is actually faster when exceptions are raised
frequently. In this manner, I solve the performance issue on Linux.
  • Loading branch information
GiovanniBussi committed Jul 19, 2021
1 parent 8f0d062 commit 0ed75e9
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 65 deletions.
99 changes: 37 additions & 62 deletions src/tools/Tools.cpp
Expand Up @@ -37,49 +37,43 @@
namespace PLMD {

template<class T>
void Tools::convertToAny(const std::string & str,T & t) {
bool Tools::convertToAny(const std::string & str,T & t) {
std::istringstream istr(str.c_str());
bool ok=static_cast<bool>(istr>>t);
if(!ok) throw ExceptionConversionError() <<"trying to convert " << str;
if(!ok) return false;
std::string remaining;
istr>>remaining;
if(remaining.length()>0) {
throw ExceptionConversionError() <<"trying to convert " << str << " remaining: "<<remaining.length();
}
return remaining.length()==0;
}

void Tools::convert(const std::string & str,int & t) {
convertToInt(str,t);
if(!convertToInt(str,t)) throw ExceptionConversionError() <<"trying to convert " << str << " to int";
}

void Tools::convert(const std::string & str,long int & t) {
convertToInt(str,t);
if(!convertToInt(str,t)) throw ExceptionConversionError() <<"trying to convert " << str << " to long int";
}

void Tools::convert(const std::string & str,unsigned & t) {
convertToInt(str,t);
if(!convertToInt(str,t)) throw ExceptionConversionError() <<"trying to convert " << str << " to unsigned";
}

void Tools::convert(const std::string & str,long unsigned & t) {
convertToInt(str,t);
if(!convertToInt(str,t)) throw ExceptionConversionError() <<"trying to convert " << str << " to long unsigned";
}

void Tools::convert(const std::string & str,AtomNumber &a) {
// Note: AtomNumber's are NOT converted as int, so as to
// avoid using lepton conversions.
unsigned i;
convertToAny(str,i);
if(!convertToAny(str,i)) throw ExceptionConversionError() <<"trying to convert " << str << " to AtomNumber";
a.setSerial(i);
}

template<class T>
void Tools::convertToInt(const std::string & str,T & t) {
bool Tools::convertToInt(const std::string & str,T & t) {
// First try standard conversion
try {
convertToAny(str,t);
return;
} catch(ExceptionConversionError& exc) {
}
if(convertToAny(str,t)) return true;
// Then use lepton
try {
double r=lepton::Parser::parse(str).evaluate(lepton::Constants());
Expand All @@ -88,84 +82,77 @@ void Tools::convertToInt(const std::string & str,T & t) {

// it should not overflow the requested int type:
// (see https://stackoverflow.com/a/526092)
if(r>std::nextafter(std::numeric_limits<T>::max(), 0)) throw ExceptionConversionError() <<"overflow converting "<<str;
if(r<std::nextafter(std::numeric_limits<T>::min(), 0)) throw ExceptionConversionError() <<"underflow converting "<<str;
if(r>std::nextafter(std::numeric_limits<T>::max(), 0)) return false;
if(r<std::nextafter(std::numeric_limits<T>::min(), 0)) return false;

// do the actual conversion
auto tmp=static_cast<T>(std::round(r));

// it should be *very close* to itself if converted back to double
double diff= r-static_cast<double>(tmp);
if(diff*diff > 1e-20) throw ExceptionConversionError() <<"non integer converting "<<str;
if(diff*diff > 1e-20) return false;
// this is to accomodate small numerical errors and allow e.g. exp(log(7)) to be integer

// it should be change if incremented or decremented by one (see https://stackoverflow.com/a/43656140)
if(r == static_cast<double>(tmp-1)) throw ExceptionConversionError() <<"non integer converting "<<str;
if(r == static_cast<double>(tmp+1)) throw ExceptionConversionError() <<"non integer converting "<<str;
if(r == static_cast<double>(tmp-1)) return false;
if(r == static_cast<double>(tmp+1)) return false;

// everything is fine, then store in t
t=tmp;
return;
return true;
} catch(PLMD::lepton::Exception& exc) {
}
throw ExceptionConversionError() <<"converting "<<str;
return false;
}


template<class T>
void Tools::convertToReal(const std::string & str,T & t) {
try {
convertToAny(str,t);
return;
} catch(ExceptionConversionError& exc) {
}
bool Tools::convertToReal(const std::string & str,T & t) {
if(convertToAny(str,t)) return true;
if(str=="PI" || str=="+PI" || str=="+pi" || str=="pi") {
t=pi; return;
t=pi; return true;
} else if(str=="-PI" || str=="-pi") {
t=-pi; return;
t=-pi; return true;
}
try {
t=lepton::Parser::parse(str).evaluate(lepton::Constants());
return;
return true;
} catch(const PLMD::lepton::Exception& exc) {
}
if( str.find("PI")!=std::string::npos ) {
std::size_t pi_start=str.find_first_of("PI");
if(str.substr(pi_start)!="PI") throw ExceptionConversionError() <<"converting " <<str;
if(str.substr(pi_start)!="PI") return false;
std::istringstream nstr(str.substr(0,pi_start));
T ff=0.0; bool ok=static_cast<bool>(nstr>>ff);
if(!ok) throw ExceptionConversionError() <<"converting "<<str;
if(!ok) return false;
t=ff*pi;
std::string remains; nstr>>remains;
if(remains.length()>0) throw ExceptionConversionError() <<"trying to convert " << str << " remaining: "<<remains.length();
return;
return remains.length()==0;
} else if( str.find("pi")!=std::string::npos ) {
std::size_t pi_start=str.find_first_of("pi");
if(str.substr(pi_start)!="pi") throw ExceptionConversionError() <<"converting " <<str;
if(str.substr(pi_start)!="pi") return false;
std::istringstream nstr(str.substr(0,pi_start));
T ff=0.0; bool ok=static_cast<bool>(nstr>>ff);
if(!ok) throw ExceptionConversionError() <<"converting "<<str;
if(!ok) return false;
t=ff*pi;
std::string remains; nstr>>remains;
if(remains.length()>0) throw ExceptionConversionError() <<"trying to convert " << str << " remaining: "<<remains.length();
return;
return remains.length()==0;
} else if(str=="NAN") {
t=std::numeric_limits<double>::quiet_NaN();
return;
return true;
}
throw ExceptionConversionError() <<"converting "<<str;
return false;
}

void Tools::convert(const std::string & str,float & t) {
convertToReal(str,t);
if(!convertToReal(str,t)) throw ExceptionConversionError() <<"trying to convert " << str << " to float";
}

void Tools::convert(const std::string & str,double & t) {
convertToReal(str,t);
if(!convertToReal(str,t)) throw ExceptionConversionError() <<"trying to convert " << str << " to double";
}

void Tools::convert(const std::string & str,long double & t) {
convertToReal(str,t);
if(!convertToReal(str,t)) throw ExceptionConversionError() <<"trying to convert " << str << " to long double";
}

void Tools::convert(const std::string & str,std::string & t) {
Expand Down Expand Up @@ -317,27 +304,15 @@ void Tools::interpretRanges(std::vector<std::string>&s) {
size_t dash=p.find("-");
if(dash==std::string::npos) continue;
int first;
try {
Tools::convertToAny(p.substr(0,dash),first);
} catch(ExceptionConversionError& exc) {
continue;
}
if(!Tools::convertToAny(p.substr(0,dash),first)) continue;
int stride=1;
int second;
size_t colon=p.substr(dash+1).find(":");
if(colon!=std::string::npos) {
try {
Tools::convertToAny(p.substr(dash+1).substr(0,colon),second);
Tools::convertToAny(p.substr(dash+1).substr(colon+1),stride);
} catch(ExceptionConversionError& exc) {
continue;
}
if(!Tools::convertToAny(p.substr(dash+1).substr(0,colon),second) ||
!Tools::convertToAny(p.substr(dash+1).substr(colon+1),stride)) continue;
} else {
try {
Tools::convertToAny(p.substr(dash+1),second);
} catch(ExceptionConversionError& exc) {
continue;
}
if(!Tools::convertToAny(p.substr(dash+1),second)) continue;
}
news.resize(news.size()-1);
if(first<=second) {
Expand Down
6 changes: 3 additions & 3 deletions src/tools/Tools.h
Expand Up @@ -55,14 +55,14 @@ const double pi(3.14159265358979323846264338327950288419716939937510582097494459
class Tools {
/// class to convert a string to a generic type T
template<class T>
static void convertToAny(const std::string & str,T &t);
static bool convertToAny(const std::string & str,T &t);
/// class to convert a string to a real type T.
/// T should be either float, double, or long double
template<class T>
static void convertToReal(const std::string & str,T &t);
static bool convertToReal(const std::string & str,T &t);
/// class to convert a string to a int type T
template<class T>
static void convertToInt(const std::string & str,T &t);
static bool convertToInt(const std::string & str,T &t);
public:
/// Split the line in words using separators.
/// It also take into account parenthesis. Outer parenthesis found are removed from
Expand Down

1 comment on commit 0ed75e9

@PlumedBot
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found broken examples in automatic/performance-optimization.txt
Found broken examples in automatic/a-trieste-6.txt
Found broken examples in automatic/munster.txt
Found broken examples in automatic/ANN.tmp
Found broken examples in automatic/EDS.tmp
Found broken examples in automatic/EMMI.tmp
Found broken examples in automatic/FOURIER_TRANSFORM.tmp
Found broken examples in automatic/FUNCPATHGENERAL.tmp
Found broken examples in automatic/FUNCPATHMSD.tmp
Found broken examples in automatic/FUNNEL.tmp
Found broken examples in automatic/FUNNEL_PS.tmp
Found broken examples in automatic/GHBFIX.tmp
Found broken examples in automatic/INCLUDE.tmp
Found broken examples in automatic/MAZE_MEMETIC_SAMPLING.tmp
Found broken examples in automatic/MAZE_OPTIMIZER_BIAS.tmp
Found broken examples in automatic/MAZE_RANDOM_ACCELERATION_MD.tmp
Found broken examples in automatic/MAZE_RANDOM_WALK.tmp
Found broken examples in automatic/MAZE_SIMULATED_ANNEALING.tmp
Found broken examples in automatic/MAZE_STEERED_MD.tmp
Found broken examples in automatic/PIV.tmp
Found broken examples in automatic/PLUMED.tmp
Found broken examples in automatic/VES_DELTA_F.tmp
Found broken examples in MiscelaneousPP.md

Please sign in to comment.