Skip to content

Instantly share code, notes, and snippets.

@akindyakov
Created August 9, 2017 08:13
Show Gist options
  • Save akindyakov/a937f25e28c973e720d30e3b6d307c0f to your computer and use it in GitHub Desktop.
Save akindyakov/a937f25e28c973e720d30e3b6d307c0f to your computer and use it in GitHub Desktop.
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
#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