# HG changeset patch # User Benjamin Golinvaux # Date 1574277923 -3600 # Node ID bf08d28bc652d859202cdeaccd8973e8039c5541 # Parent f68da12e852b9bcf4a8c748be4e093d55fc33d20 Added timing tests diff -r f68da12e852b -r bf08d28bc652 UnitTestsSources/GenericToolboxTests.cpp --- a/UnitTestsSources/GenericToolboxTests.cpp Wed Nov 20 10:47:42 2019 +0100 +++ b/UnitTestsSources/GenericToolboxTests.cpp Wed Nov 20 20:25:23 2019 +0100 @@ -20,10 +20,15 @@ #include +#include +#include + #include "gtest/gtest.h" #include "stdint.h" +#include + TEST(GenericToolbox, TestLegitDoubleString) { using OrthancStone::GenericToolbox::LegitDoubleString; @@ -3840,6 +3845,112 @@ } } +static const size_t NUM_TIMINGS_CONVS = 2000; + + +//4444444444444444$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ + +TEST(GenericToolbox, TestStringToDoubleHardNeg_lexical_cast_vs_StringToDouble) +{ + using OrthancStone::GenericToolbox::StringToDouble; + const double TOLERANCE = 0.00000000000001; + + double total_us_StringToDouble = 0.0; + double total_us_lexical_cast = 0.0; + int64_t numConversions = 0; + + size_t i = 0; + const size_t COUNT = 125; + //const double FACTOR = 1.000000000171271211; + const double FACTOR = 1.71271211; + for (double b = -1.0 * DBL_EPSILON; b < DBL_MAX && i < COUNT; ++i, b *= FACTOR) + { + char txt[1024]; +#if defined(_MSC_VER) + sprintf_s(txt, "%.17f", b); +#else + snprintf(txt, sizeof(txt) - 1, "%.17f", b); +#endif + + + double r = 0.0; + + bool ok = true; + + { + boost::chrono::system_clock::time_point start = boost::chrono::system_clock::now(); + for (size_t i = 0; i < NUM_TIMINGS_CONVS; ++i) + { + ok = StringToDouble(r, txt); + } + boost::chrono::system_clock::time_point end = boost::chrono::system_clock::now(); + boost::chrono::microseconds elapsed = + boost::chrono::duration_cast(end - start); + total_us_StringToDouble += elapsed.count(); + } + + { + boost::chrono::system_clock::time_point start = boost::chrono::system_clock::now(); + for (size_t i = 0; i < NUM_TIMINGS_CONVS; ++i) + { + try + { + r = boost::lexical_cast(txt); + ok = true; + } + catch (boost::bad_lexical_cast& ) + { + ok = false; + } + } + boost::chrono::system_clock::time_point end = boost::chrono::system_clock::now(); + boost::chrono::microseconds elapsed = + boost::chrono::duration_cast(end - start); + total_us_lexical_cast += elapsed.count(); + } + numConversions += NUM_TIMINGS_CONVS; + +#if 0 + if (ok) + { + printf("OK for txt = \"%s\" and r = %.17f\n", txt, r); + } + else + { + printf("Not ok for txt = \"%s\" and r = %.17f\n", txt, r); + ok = StringToDouble(r, txt); + } +#endif + + EXPECT_TRUE(ok); + +#if 0 + if (fabs(b - r) > TOLERANCE) + { + printf("fabs(b (%.17f) - r (%.17f)) ((%.17f)) > TOLERANCE (%.17f)\n", b, r, fabs(b - r), TOLERANCE); + } +#endif + EXPECT_NEAR(b, r, TOLERANCE); + } + std::cout << "Total time (us) for " << numConversions + << " conversions using StringToDouble (with NO scientific notation) = " + << static_cast(total_us_StringToDouble) << std::endl; + + std::cout << "Time per conversion using StringToDouble (ns) = " + << (int64_t)( (total_us_StringToDouble * 1000) /((double)numConversions)) << std::endl; + + std::cout << "Total time (us) for " << numConversions + << " conversions using boost::lexical_cast (with NO scientific notation) = " + << static_cast(total_us_lexical_cast) << std::endl; + + std::cout << "Time per conversion using boost::lexical_cast (ns) = " + << (int64_t)( (total_us_lexical_cast * 1000) / ((double)numConversions)) << std::endl; + + std::cout << "StringToDouble is " << (int)((total_us_lexical_cast / total_us_StringToDouble) + 0.5) << " times faster than boost::lexical_cast" << std::endl; + +} +//4444444444444444$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ + TEST(GenericToolbox, TestStringToDoubleHardScientific) { @@ -3953,6 +4064,117 @@ } +TEST(GenericToolbox, TestStringToDoubleHardNegScientific_lexical_cast_vs_StringToDouble) +{ + using OrthancStone::GenericToolbox::StringToDouble; + const double TOLERANCE = 0.00000000000001; + + size_t i = 0; + const size_t COUNT = 125; + //const double FACTOR = 1.000000000171271211; + const double FACTOR = 1.71271211; + + double total_us_StringToDouble = 0.0; + double total_us_lexical_cast = 0.0; + int64_t numConversions = 0; + + for (double b = -1.0 * DBL_EPSILON; b < DBL_MAX && i < COUNT; ++i, b *= FACTOR) + { + // the tolerance must be adapted depending on the exponent + double exponent = (b == 0) ? 0 : 1.0 + std::floor(std::log10(std::fabs(b))); + double actualTolerance = TOLERANCE * pow(10.0, exponent); + + char txt[1024]; +#if defined(_MSC_VER) + sprintf_s(txt, "%.17e", b); +#else + snprintf(txt, sizeof(txt) - 1, "%.17e", b); +#endif + double r = 0.0; + + bool ok = true; + + { + boost::chrono::system_clock::time_point start = boost::chrono::system_clock::now(); + for (size_t i = 0; i < NUM_TIMINGS_CONVS; ++i) + { + ok = StringToDouble(r, txt); + } + boost::chrono::system_clock::time_point end = boost::chrono::system_clock::now(); + boost::chrono::microseconds elapsed = + boost::chrono::duration_cast(end - start); + total_us_StringToDouble += elapsed.count(); + } + + { + boost::chrono::system_clock::time_point start = boost::chrono::system_clock::now(); + for (size_t i = 0; i < NUM_TIMINGS_CONVS; ++i) + { + try + { + r = boost::lexical_cast(txt); + ok = true; + } + catch (boost::bad_lexical_cast& ) + { + ok = false; + } + } + boost::chrono::system_clock::time_point end = boost::chrono::system_clock::now(); + boost::chrono::microseconds elapsed = + boost::chrono::duration_cast(end - start); + total_us_lexical_cast += elapsed.count(); + } + numConversions += NUM_TIMINGS_CONVS; + +#if 0 + if (ok) + { + printf("OK for txt = \"%s\" and r = %.17e\n", txt, r); + } + else + { + printf("Not ok for txt = \"%s\" and r = %.17e\n", txt, r); + ok = StringToDouble(r, txt); + } +#endif + + EXPECT_TRUE(ok); + +#if 0 + if (fabs(b - r) > actualTolerance) + { + printf("NOK fabs(b (%.17f) - r (%.17f)) ((%.17f)) > actualTolerance (%.17f)\n", b, r, fabs(b - r), actualTolerance); + printf("NOK fabs(b (%.17e) - r (%.17e)) ((%.17e)) > actualTolerance (%.17e)\n", b, r, fabs(b - r), actualTolerance); + ok = StringToDouble(r, txt); + } + else + { + printf("OK fabs(b (%.17f) - r (%.17f)) ((%.17f)) <= actualTolerance (%.17f)\n", b, r, fabs(b - r), actualTolerance); + printf("OK fabs(b (%.17e) - r (%.17e)) ((%.17e)) <= actualTolerance (%.17e)\n", b, r, fabs(b - r), actualTolerance); + } +#endif + EXPECT_NEAR(b, r, actualTolerance); + } + + std::cout << "Total time (us) for " << numConversions + << " conversions using StringToDouble (WITH scientific notation) = " + << static_cast(total_us_StringToDouble) << std::endl; + + std::cout << "Time per conversion using StringToDouble (ns) = " + << (int64_t)( (total_us_StringToDouble*1000) / ((double)numConversions)) << std::endl; + + std::cout << "Total time (us) for " << numConversions + << " conversions using boost::lexical_cast (WITH scientific notation) = " + << static_cast(total_us_lexical_cast) << std::endl; + + std::cout << "Time per conversion using boost::lexical_cast (ns) = " + << (int64_t)( (total_us_lexical_cast * 1000) / ((double)numConversions)) << std::endl; + + std::cout << "StringToDouble is " << (int)((total_us_lexical_cast / total_us_StringToDouble)+ 0.5) << " times faster than boost::lexical_cast" << std::endl; +} + + TEST(GenericToolbox, TestStringToIntegerHard) { using OrthancStone::GenericToolbox::StringToInteger;