Last active
August 9, 2017 08:15
-
-
Save akindyakov/2c528beccb11a24c1e6ec02ec12df47e to your computer and use it in GitHub Desktop.
double-conversion string to float benchmark
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ ./a.out | |
equality test: passed | |
float (Tensoflow): Time: 7.51398 s | |
float (double-conversion): Time: 0.371179 s | |
float (boost): Time: 3.03555 s | |
float (Tensoflow): Time: 7.43642 s | |
float (double-conversion): Time: 0.412458 s | |
float (boost): Time: 3.28229 s |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <chrono> | |
#include <cstring> | |
#include <stdexcept> | |
#include <iostream> | |
#include <limits> | |
#include <sstream> | |
#include <string> | |
#include <unordered_map> | |
#include <vector> | |
#include <cmath> | |
#include <boost/lexical_cast.hpp> | |
#include "double-conversion.h" | |
auto samples = std::vector<std::string>{ | |
"0.0139571", | |
"-0.200695", | |
"0.425701", | |
"0.321992", | |
"-0.29584", | |
"-0.369174", | |
"-0.221044", | |
"-0.85417", | |
"0.371563", | |
"-0.690481", | |
"-0.533224", | |
"0.632799", | |
"-0.31973", | |
"-0.138462", | |
"0.0180235", | |
"-0.073256", | |
"-0.0905731", | |
"0.26389", | |
"0.480459", | |
"0.487908", | |
"0.659123", | |
"-0.0815248", | |
"-0.937797", | |
"-0.0977258", | |
"-0.679483", | |
"-0.310219", | |
"0.780157", | |
"-0.891381", | |
"0.514362", | |
"-0.454578", | |
"-0.0845889", | |
"0.739676", | |
"-0.281231", | |
"-0.799154", | |
"-0.769359", | |
"0.0958071", | |
"-0.843933", | |
"0.778958", | |
"-0.535816", | |
"-0.69228", | |
"0.411554", | |
"0.149806", | |
"-0.80259", | |
"-0.844836", | |
"-0.0969906", | |
"-0.565188", | |
"-0.772835", | |
"0.0597194", | |
"-0.511505", | |
"-0.405", | |
"-0.561984", | |
"0.0174952", | |
"-0.154", | |
"0.190967", | |
"0.0393466", | |
"0.56354", | |
"-0.0179746", | |
"-0.869477", | |
"0.47105", | |
"-0.841792", | |
"-0.250595", | |
"0.516145", | |
"0.0162257", | |
"-0.413626", | |
"-0.938293", | |
"-0.860529", | |
"-0.349912", | |
"-0.812397", | |
"-0.709884", | |
"0.781196", | |
"0.213943", | |
"0.572334", | |
"-0.295616", | |
"-0.0590044", | |
"-0.991228", | |
"0.903635", | |
"-0.5928", | |
"-0.297474", | |
"0.579006", | |
"-0.27914", | |
"-0.230229", | |
"0.31037", | |
"-0.860558", | |
"0.394183", | |
"-0.70807", | |
"-0.856649", | |
"-0.745867", | |
"-0.884001", | |
"-0.0483891", | |
"-0.543972", | |
"-0.533639", | |
"-0.801926", | |
"0.98913", | |
"-0.450537", | |
"-0.496088", | |
"0.531625", | |
"0.715522", | |
"0.0639623", | |
"-0.744005", | |
"0.97367", | |
"-0.313371", | |
"0.892952", | |
"-0.11367", | |
"-0.845039", | |
"0.131992", | |
"0.0404928", | |
"0.301242", | |
"-0.0351033", | |
"0.5041", | |
"-0.700904", | |
"-0.315441", | |
"-0.136286", | |
"0.85399", | |
"-0.433727", | |
"0.252876", | |
"-0.724682", | |
"0.109293", | |
"-0.602706", | |
"0.97699", | |
"0.976375", | |
"0.738014", | |
"0.352822", | |
"0.867106", | |
"0.659885", | |
"-0.487436", | |
"-0.634312", | |
"-0.35495", | |
"-0.745179", | |
"-0.286691", | |
"-0.146203", | |
"-0.71323", | |
"0.822713", | |
"-0.295751", | |
"-0.523745", | |
"0.123595", | |
"-0.30038", | |
"0.937056", | |
"-0.185249", | |
"0.196027", | |
"-0.26587", | |
"-0.217106", | |
"0.540099", | |
"0.298851", | |
"0.645519", | |
"-0.031627", | |
"-0.102341", | |
"0.861288", | |
"0.600994", | |
"0.358774", | |
"0.999048", | |
"-0.930462", | |
"-0.471824", | |
"0.133737", | |
"0.326803", | |
"0.853633", | |
"-0.55504", | |
"-0.273402", | |
"-0.418553", | |
"0.800543", | |
"0.407464", | |
"-0.555079", | |
"0.667143", | |
"0.657574", | |
"0.231786", | |
"-0.532958", | |
"0.11798", | |
"-0.438847", | |
"0.957759", | |
"0.904551", | |
"0.980619", | |
"-0.241317", | |
"-0.473036", | |
"0.0502874", | |
"0.944594", | |
"0.0716108", | |
"-0.527947", | |
"0.153495", | |
"0.776737", | |
"0.903343", | |
"0.412055", | |
"-0.45461", | |
"-0.133498", | |
"-0.700291", | |
"-0.207772", | |
"-0.92029", | |
"0.223498", | |
"-0.518201", | |
"0.914808", | |
"-0.639733", | |
"-0.41297", | |
"0.902391", | |
"0.896143", | |
"-0.800626", | |
"0.112141", | |
"0.868971", | |
"-0.79964", | |
"-0.261114", | |
"0.412841", | |
"0.195498", | |
"-0.201019", | |
"-0.612011", | |
"0.35395", | |
"0.868427", | |
"-0.181431", | |
"0.173795", | |
"0.211635", | |
"0.992459", | |
"0.638112", | |
"0.872352", | |
"0.494873", | |
"-0.837919", | |
"-0.952635", | |
"-0.677662", | |
"-0.499694", | |
"0.0841749", | |
"0.0187345", | |
"0.0637829", | |
"0.719815", | |
"0.170137", | |
"0.0569379", | |
"0.746321", | |
"0.736631", | |
"-0.758605", | |
"0.345146", | |
"-0.243856", | |
"-0.00235319", | |
"-0.73814", | |
"-0.75527", | |
"0.515668", | |
"-0.0608916", | |
"0.188299", | |
"0.484145", | |
"-0.847359", | |
"0.897868", | |
"-0.251745", | |
"0.401244", | |
"0.545742", | |
"0.752535", | |
"0.49086", | |
"0.914568", | |
"0.72635", | |
"0.648184", | |
"0.0177184", | |
"-0.757956", | |
"-0.590032", | |
"0.906946", | |
"0.60505", | |
"-0.115929", | |
"-0.147576", | |
"0.88006", | |
"0.822675", | |
"0.168301", | |
"-0.679297", | |
"0.581888", | |
"-0.385499", | |
"0.188192", | |
"-0.326248", | |
"0.484408", | |
"-0.128408", | |
"-0.578289", | |
"-0.439749", | |
"-0.080506", | |
"-0.513015", | |
"-0.152826", | |
"0.827369", | |
"-0.455285", | |
"-0.620707", | |
"-0.312022", | |
"0.270523", | |
"-0.412034", | |
"-0.234054", | |
"0.556896", | |
"0.385488", | |
"-0.512513", | |
"-0.217134", | |
"0.993917", | |
"-0.593129", | |
"-0.333381", | |
"-0.669388", | |
"-0.626429", | |
"0.523095", | |
"0.590044", | |
"0.111681", | |
"-0.198555", | |
"0.476492", | |
"-0.264509", | |
"0.720245", | |
"0.474338", | |
"-0.0499685", | |
"-0.503044", | |
"0.498012", | |
"0.322014", | |
"-0.609043", | |
"0.547355", | |
"0.80818", | |
"0.228808", | |
"-0.538766", | |
"0.761539", | |
"0.27535", | |
"0.871801", | |
"-0.601997", | |
"-0.276533", | |
"-0.158569", | |
"-0.151035", | |
"-0.721874", | |
"0.867062", | |
"0.277705", | |
"0.698371", | |
"0.564961", | |
"-0.71355", | |
"-0.524697", | |
"-0.0695089", | |
"0.432998", | |
"-0.657424", | |
"0.0838801", | |
"-0.918741", | |
"0.911136", | |
"-0.637049", | |
"-0.949542", | |
"-0.677877", | |
"0.951001", | |
"-0.300082", | |
"0.322574", | |
"0.75321", | |
"-0.816419", | |
"-0.0058701", | |
"-0.519222", | |
"0.479385", | |
"-0.960985", | |
"0.42363", | |
"0.484492", | |
"0.75183", | |
"-0.668698", | |
"-0.750568", | |
"0.333608", | |
"0.192101", | |
"-0.612033", | |
"-0.53537", | |
"-0.935502", | |
"0.414689", | |
"-0.0617934", | |
"-0.83568", | |
"0.642611", | |
"0.18851", | |
"0.906932", | |
"-0.655471", | |
"0.146353", | |
"-0.414732", | |
"-0.612848", | |
"0.382117", | |
"0.994753", | |
"-0.273407", | |
"0.794697", | |
"-0.97567", | |
"0.514064", | |
"0.367029", | |
"-0.278538", | |
"-0.0592746", | |
"-0.527806", | |
"-0.40581", | |
"-0.985888", | |
"0.763042", | |
"-0.473923", | |
"-0.237774", | |
"0.483321", | |
"-0.437065", | |
"-0.771389", | |
"0.91659", | |
"0.511042", | |
"0.0700364", | |
"-0.893302", | |
"-0.922069", | |
"-0.72786", | |
"0.275039", | |
"0.0918438", | |
"0.891018", | |
"0.338968", | |
"-0.103573", | |
"-0.0787736", | |
"-0.678809", | |
"0.896115", | |
"0.718237", | |
"0.26254", | |
"0.704854", | |
"0.307236", | |
"-0.667049", | |
"0.168811", | |
"0.21703", | |
"-0.631729", | |
"-0.710091", | |
"-0.773553", | |
"-0.851957", | |
"-0.463308", | |
"0.805836", | |
"-0.37184", | |
"0.566039", | |
"-0.0251418", | |
"0.235281", | |
"0.598512", | |
"0.710005", | |
"0.678882", | |
"-0.19268", | |
"-0.604042", | |
"-0.0254462", | |
"-0.787204", | |
"-0.224884", | |
"0.456558", | |
"0.518357", | |
"-0.677267", | |
"0.391889", | |
"0.812003", | |
"-0.336941", | |
"0.299354", | |
"-0.143103", | |
"-0.798676", | |
"0.254422", | |
"0.0289669", | |
"-0.691397", | |
"0.762811", | |
"-0.781752", | |
"-0.373312", | |
"-0.251013", | |
"-0.0819849", | |
"0.449412", | |
"0.711468", | |
"-0.544033", | |
"0.589841", | |
"-0.82005", | |
"-0.940033", | |
"0.320849", | |
"0.891287", | |
"-0.666082", | |
"0.316406", | |
"-0.674723", | |
"-0.386398", | |
"-0.596249", | |
"-0.462285", | |
"0.404745", | |
"-0.152991", | |
"0.0652113", | |
"0.797204", | |
"-0.388822", | |
"-0.245062", | |
"0.669348", | |
"-0.470041", | |
"0.911956", | |
"0.940391", | |
"-0.408113", | |
"0.670256", | |
"0.925705", | |
"-0.822625", | |
"0.155023", | |
"-0.403771", | |
"0.47674", | |
"0.93564", | |
"0.419714", | |
"-0.589921", | |
"0.981358", | |
"0.507952", | |
"-0.355269", | |
"0.90112", | |
"-0.367132", | |
"-0.394473", | |
"-0.762166", | |
"-0.102247", | |
"0.701401", | |
"-0.588725", | |
"0.336772", | |
"0.141483", | |
"-0.450602", | |
"-0.693607", | |
"-0.373079", | |
"0.359553", | |
"0.845372", | |
"0.525277", | |
"-0.92146", | |
"0.95407", | |
"-0.705511", | |
"0.590754", | |
"-0.00646037", | |
"-0.659594", | |
"-0.100466", | |
"0.848128", | |
"0.649835", | |
"-0.0082866", | |
"0.754135", | |
"0.21947", | |
"-0.618087", | |
"-0.859216", | |
"-0.64024", | |
"0.535243", | |
"-0.787084", | |
"0.0676093", | |
"-0.558468", | |
"0.87362", | |
"-0.275776", | |
"0.210151", | |
"0.73091", | |
"-0.0422017", | |
"-0.842047", | |
"0.479343", | |
"0.92407", | |
"0.929218", | |
"0.411008", | |
"0.0590026", | |
"-0.453324", | |
"0.475808", | |
"-0.0145319", | |
"0.939003", | |
"0.170918", | |
"-0.771814", | |
"0.732009", | |
"-0.0287602", | |
"0.181965", | |
"-0.560092", | |
"-0.272431", | |
"-0.954687", | |
"-0.582682", | |
"-0.018676", | |
"0.197328", | |
"0.395256", | |
"0.909606", | |
"-0.808966", | |
"-0.786559", | |
"0.173814", | |
"-0.729962", | |
"0.388828", | |
"0.21038", | |
"-0.939213", | |
"0.143536", | |
"-0.0450968", | |
"-0.00809681", | |
"-0.704608", | |
"0.574393", | |
"0.981113", | |
"0.140189", | |
"-0.444382", | |
"-0.730953", | |
"-0.855921", | |
"-0.00707525", | |
"0.613503", | |
"-0.5239", | |
"0.16448", | |
"0.29225", | |
"0.996138", | |
"-0.796216", | |
"0.604062", | |
"0.0146031", | |
"-0.510791", | |
"0.358454", | |
"0.154993", | |
"-0.965694", | |
"-0.875001", | |
"0.388019", | |
"-0.469789", | |
"0.673432", | |
"0.105272", | |
"0.874507", | |
"0.369318", | |
"-0.445472", | |
"-0.307395", | |
"0.317084", | |
"0.863438", | |
"-0.325786", | |
"-0.499459", | |
"-0.790636", | |
"-0.131223", | |
"-0.95241", | |
"-0.53152", | |
"0.34577", | |
"-0.740624", | |
"-0.46758", | |
"0.224461", | |
"0.938087", | |
"-0.704064", | |
"-0.748881", | |
"0.106128", | |
"-0.687262", | |
"-0.420383", | |
"0.358502", | |
"-0.113538", | |
"0.872809", | |
"-0.0391968", | |
"0.201448", | |
"0.69152", | |
"0.362478", | |
"-0.609919", | |
"0.333546", | |
"0.683449", | |
"-0.827019", | |
"-0.835349", | |
"-0.541856", | |
"0.527473", | |
"-0.64772", | |
"-0.023896", | |
"-0.99251", | |
"-0.894629", | |
"-0.976152", | |
"0.010522", | |
"0.435339", | |
"-0.773189", | |
"0.500428", | |
"-0.631044", | |
"0.117688", | |
"0.212068", | |
"-0.838193", | |
"0.441427", | |
"-0.78569", | |
"-0.471192", | |
"0.437807", | |
"-0.674532", | |
"-0.69821", | |
"-0.00515276", | |
"-0.970084", | |
"0.691756", | |
"0.944928", | |
"-0.520862", | |
"-0.767211", | |
"-0.10637", | |
"0.755792", | |
"0.451552", | |
"0.734564", | |
"-0.10707", | |
"-0.484953", | |
"-0.681139", | |
"0.911562", | |
"0.439623", | |
"0.637457", | |
"0.244489", | |
"-0.490466", | |
"-0.284911", | |
"0.308385", | |
"0.55094", | |
"-0.329125", | |
"-0.194692", | |
"-0.953472", | |
"-0.504807", | |
"0.147778", | |
"-0.144062", | |
"0.00889814", | |
"-0.900457", | |
"-0.583285", | |
"-0.431911", | |
"-78", | |
"78", | |
"-0.0845", | |
"1e310", | |
"0x0a", | |
"inf", | |
"inF", | |
"+iNf", | |
"-INF", | |
"-inf", | |
"nan", | |
"+nan", | |
"-naN", | |
"-Nan", | |
"+NaN", | |
"-nAn", | |
"NAN", | |
}; | |
namespace { | |
template <typename T> | |
T locale_independent_strtonum(const char* str, const char** endptr) { | |
static const std::unordered_map<std::string, T> special_nums = { | |
{"inf", std::numeric_limits<T>::infinity()}, | |
{"+inf", std::numeric_limits<T>::infinity()}, | |
{"-inf", -std::numeric_limits<T>::infinity()}, | |
{"infinity", std::numeric_limits<T>::infinity()}, | |
{"+infinity", std::numeric_limits<T>::infinity()}, | |
{"-infinity", -std::numeric_limits<T>::infinity()}, | |
{"nan", std::numeric_limits<T>::quiet_NaN()}, | |
{"+nan", std::numeric_limits<T>::quiet_NaN()}, | |
{"-nan", -std::numeric_limits<T>::quiet_NaN()}, | |
}; | |
std::stringstream s(str); | |
// Check if str is one of the special numbers. | |
std::string special_num_str; | |
s >> special_num_str; | |
for (int i = 0; i < special_num_str.length(); ++i) { | |
special_num_str[i] = | |
std::tolower(special_num_str[i], std::locale::classic()); | |
} | |
auto entry = special_nums.find(special_num_str); | |
if (entry != special_nums.end()) { | |
*endptr = str + (s.eof() ? static_cast<std::iostream::pos_type>(strlen(str)) | |
: s.tellg()); | |
return entry->second; | |
} else { | |
// Perhaps it's a hex number | |
if (special_num_str.compare(0, 2, "0x") == 0 || | |
special_num_str.compare(0, 3, "-0x") == 0) { | |
return strtol(str, const_cast<char**>(endptr), 16); | |
} | |
} | |
// Reset the stream | |
s.str(str); | |
s.clear(); | |
// Use the "C" locale | |
s.imbue(std::locale::classic()); | |
T result; | |
s >> result; | |
// Set to result to what strto{f,d} functions would have returned. If the | |
// number was outside the range, the stringstream sets the fail flag, but | |
// returns the +/-max() value, whereas strto{f,d} functions return +/-INF. | |
if (s.fail()) { | |
if (result == std::numeric_limits<T>::max()) { | |
result = std::numeric_limits<T>::infinity(); | |
s.clear(s.rdstate() & ~std::ios::failbit); | |
} else if (result == -std::numeric_limits<T>::max()) { | |
result = -std::numeric_limits<T>::infinity(); | |
s.clear(s.rdstate() & ~std::ios::failbit); | |
} | |
} | |
if (endptr) { | |
*endptr = | |
str + | |
(s.fail() ? static_cast<std::iostream::pos_type>(0) | |
: (s.eof() ? static_cast<std::iostream::pos_type>(strlen(str)) | |
: s.tellg())); | |
} | |
return result; | |
} | |
} // namespace | |
bool safe_strtof_tf(const char* str, float* value) { | |
const char* endptr; | |
*value = locale_independent_strtonum<float>(str, &endptr); | |
while (isspace(*endptr)) ++endptr; | |
// Ignore range errors from strtod/strtof. | |
// The values it returns on underflow and | |
// overflow are the right fallback in a | |
// robust setting. | |
return *str != '\0' && *endptr == '\0'; | |
} | |
bool safe_strtod_tf(const char* str, double* value) { | |
const char* endptr; | |
*value = locale_independent_strtonum<double>(str, &endptr); | |
while (isspace(*endptr)) ++endptr; | |
// Ignore range errors from strtod/strtof. | |
// The values it returns on underflow and | |
// overflow are the right fallback in a | |
// robust setting. | |
return *str != '\0' && *endptr == '\0'; | |
} | |
static inline const double_conversion::StringToDoubleConverter& StringToFloatConverter() { | |
const static double_conversion::StringToDoubleConverter converter( | |
double_conversion::StringToDoubleConverter::ALLOW_LEADING_SPACES | |
| double_conversion::StringToDoubleConverter::ALLOW_HEX | |
| double_conversion::StringToDoubleConverter::ALLOW_OCTALS | |
| double_conversion::StringToDoubleConverter::ALLOW_TRAILING_SPACES | |
| double_conversion::StringToDoubleConverter::ALLOW_CASE_INSENSIBILITY, | |
0., 0., "inf", "nan" | |
); | |
return converter; | |
} | |
static const int kFastToBufferSize = 32; | |
bool safe_strtof_dc(const char* str, float* value) { | |
int processed_characters_count = -1; | |
auto len = strnlen(str, kFastToBufferSize); | |
*value = StringToFloatConverter().StringToFloat( | |
str, | |
len, | |
&processed_characters_count); | |
return processed_characters_count > 0; | |
} | |
bool safe_strtod_dc(const char* str, double* value) { | |
int processed_characters_count = -1; | |
auto len = strnlen(str, kFastToBufferSize); | |
*value = StringToFloatConverter().StringToDouble( | |
str, | |
len, | |
&processed_characters_count); | |
return processed_characters_count > 0; | |
} | |
bool safe_strtof_boost(const char* str, float* value) { | |
try { | |
*value = boost::lexical_cast<float>(str); | |
} catch (const boost::bad_lexical_cast& err) { | |
*value = std::numeric_limits<float>::quiet_NaN(); | |
//return false; | |
} | |
return true; | |
} | |
bool safe_strtod_boost(const char* str, double* value) { | |
try { | |
*value = boost::lexical_cast<double>(str); | |
} catch (const boost::bad_lexical_cast& err) { | |
*value = std::numeric_limits<double>::quiet_NaN(); | |
//return false; | |
} | |
return true; | |
} | |
template<typename Fn, typename T> | |
void perf_test(Fn fn, T value) { | |
auto start = std::chrono::high_resolution_clock::now(); | |
for (unsigned i = 0; i < 10000; ++i) { | |
for (const auto& s : samples) { | |
if (!fn(s.c_str(), &value)) { | |
throw std::runtime_error("parsing was failed"); | |
} | |
} | |
} | |
auto end = std::chrono::high_resolution_clock::now(); | |
std::chrono::duration<double> diff = end-start; | |
std::cout << "Time: " << diff.count() << " s\n"; | |
} | |
template<typename FnLeft, typename FnRight, typename T> | |
void equal_test(FnLeft fn_left, FnRight fn_right, T left_value) { | |
auto right_value = left_value; | |
for (const auto& s : samples) { | |
if (!fn_left(s.c_str(), &left_value)) { | |
throw std::runtime_error("left parsing has failed"); | |
} | |
if (!fn_right(s.c_str(), &right_value)) { | |
throw std::runtime_error("right parsing has failed"); | |
} | |
if (std::fabs(left_value - right_value) > std::numeric_limits<T>::epsilon()) { | |
throw std::runtime_error("right and left are not equal"); | |
} | |
} | |
} | |
int main() { | |
std::cout << "equality test: "; | |
equal_test(safe_strtod_dc, safe_strtod_tf, double{0.}); | |
equal_test(safe_strtof_dc, safe_strtof_tf, float{0.}); | |
equal_test(safe_strtod_boost, safe_strtod_tf, double{0.}); | |
equal_test(safe_strtof_boost, safe_strtof_tf, float{0.}); | |
std::cout << "passed\n"; | |
std::cout << "float (Tensoflow): "; | |
perf_test(safe_strtof_tf, float{0.}); | |
std::cout << "float (double-conversion): "; | |
perf_test(safe_strtof_dc, float{0.}); | |
std::cout << "float (boost): "; | |
perf_test(safe_strtof_boost, float{0.}); | |
std::cout << "float (Tensoflow): "; | |
perf_test(safe_strtod_tf, double{0.}); | |
std::cout << "float (double-conversion): "; | |
perf_test(safe_strtod_dc, double{0.}); | |
std::cout << "float (boost): "; | |
perf_test(safe_strtod_boost, double{0.}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment