c++ stod很慢

C++ Convert String to Double Speed

(There is also a string-to-int performance test.)

A performance benchmark of which method is faster of converting an std::string to a double. The goal is ending up with a double of the value represented in an std::string.

The tested methods are:

Source for the test is at speed-string-to-double.cpp with cycle.h.

The compilers are Microsoft Visual C++ 2010 with _SECURE_SCL disabled, GNU g++ 4.6.0, and LLVM clang++ from Arch.


Tests were run for converting 100000 string containing doubles in the range +/- 99999.99999. The result for the naive loop and atof() are set as the baseline 100% and the other numbers is time spent relative to those. The naive loop wins by a large margin, but Boost.Spirit is the fastest correct implementation.

Windows: MSVC++ 2010

  • Compiler: MSVC++ 2010 _SECURE_SCL=0
  • Arch: Windows 7 64 bit, 1.60GHz Core i7 Q720, 8 GiB RAM
VC++ 2010TicksRelative to naiveRelative to atof()
naive 4366220 1.00 0.05
atof() 82732774 18.95 1.00
strtod() 83189198 19.05 1.01
sscanf() 168568387 38.61 2.04
spirit qi 18932917 4.34 0.23
lexical_cast 332374407 76.12 4.02
stringstream 361943816 82.90 4.37
stringstream reused 240848392 55.16 2.91

Linux: GNU g++ 4.6.0

  • Compiler: GNU g++ 4.6.0 -O3
  • Arch: VirtualBox on the Windows machine, VT-x, Arch Linux, kernel 2.6.38-ARCH, 1 GiB RAM
g++ 4.6.0TicksRelative to naiveRelative to atof()
naive 4656159 1.00 0.15
atof() 30605490 6.57 1.00
strtod() 30963926 6.65 1.01
sscanf() 56235197 12.08 1.84
spirit qi 20731062 4.45 0.68
lexical_cast 139521406 29.96 4.56
stringstream 184723298 39.67 6.04
stringstream reused 100905407 21.67 3.30

Linux: LLVM clang++ 2.9

  • Compiler: clang++ 2.9 -O3
  • Arch: VirtualBox on the Windows machine, VT-x, Arch Linux, kernel 2.6.38-ARCH, 1 GiB RAM
clang++ 2.9TicksRelative to naiveRelative to atof()
naive 6804881 1.00 0.22
atof() 30829865 4.53 1.00
strtod() 30871514 4.54 1.00
sscanf() 57903993 8.51 1.88
spirit qi 24411041 3.59 0.79
lexical_cast 149339833 21.95 4.84
stringstream 191239066 28.10 6.20
stringstream reused 100461405 14.76 3.26
 
 
#ifdef _MSC_VER
    #define _SECURE_SCL 0
    #define _CRT_SECURE_NO_DEPRECATE 1
    #define WIN32_LEAN_AND_MEAN
    #define VC_EXTRALEAN
    #define NOMINMAX
#endif

#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <cmath>
#include <iostream>
#include <string>
#include <vector>
#include <iomanip>
#include <sstream>
#include <boost/lexical_cast.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include "cycle.h"

static const size_t N = 100000;
static const size_t R = 7;

void PrintStats(std::vector<double> timings) {
    double fastest = std::numeric_limits<double>::max();

    std::cout << std::fixed << std::setprecision(2);
    std::cout << "[";
    for (size_t i = 1 ; i<timings.size()-1 ; ++i) {
        fastest = std::min(fastest, timings[i]);
        std::cout << timings[i] << ",";
    }
    std::cout << timings.back();
    std::cout << "]";

    double sum = 0.0;
    for (size_t i = 1 ; i<timings.size() ; ++i) {
        sum += timings[i];
    }
    double avg = sum / static_cast<double>(timings.size()-1);

    sum = 0.0;
    for (size_t i = 1 ; i<timings.size() ; ++i) {
        timings[i] = pow(timings[i]-avg, 2);
        sum += timings[i];
    }
    double var = sum/(timings.size()-2);
    double sdv = sqrt(var);

    std::cout << " with fastest " << fastest << ", average " << avg << ", stddev " << sdv;
}

double naive(const char *p) {
    double r = 0.0;
    bool neg = false;
    if (*p == '-') {
        neg = true;
        ++p;
    }
    while (*p >= '0' && *p <= '9') {
        r = (r*10.0) + (*p - '0');
        ++p;
    }
    if (*p == '.') {
        double f = 0.0;
        int n = 0;
        ++p;
        while (*p >= '0' && *p <= '9') {
            f = (f*10.0) + (*p - '0');
            ++p;
            ++n;
        }
        r += f / std::pow(10.0, n);
    }
    if (neg) {
        r = -r;
    }
    return r;
}

int main() {
    std::vector<std::string> nums;
    nums.reserve(N);
    for (size_t i=0 ; i<N ; ++i) {
        std::string y;
        if (i & 1) {
            y += '-';
        }
        y += boost::lexical_cast<std::string>(i);
        y += '.';
        y += boost::lexical_cast<std::string>(i);
        nums.push_back(y);
    }

    {
        double tsum = 0.0;
        std::vector<double> timings;
        timings.reserve(R);
        for (size_t r=0 ; r<R ; ++r) {
            ticks start = getticks();
            for (size_t i=0 ; i<nums.size() ; ++i) {
                double x = naive(nums[i].c_str());
                tsum += x;
            }
            ticks end = getticks();
            double timed = elapsed(end, start);
            timings.push_back(timed);
        }

        std::cout << "naive: ";
        PrintStats(timings);
        std::cout << std::endl;
        std::cout << tsum << std::endl;
    }

    {
        double tsum = 0.0;
        std::vector<double> timings;
        timings.reserve(R);
        for (size_t r=0 ; r<R ; ++r) {
            ticks start = getticks();
            for (size_t i=0 ; i<nums.size() ; ++i) {
                double x = atof(nums[i].c_str());
                tsum += x;
            }
            ticks end = getticks();
            double timed = elapsed(end, start);
            timings.push_back(timed);
        }

        std::cout << "atof(): ";
        PrintStats(timings);
        std::cout << std::endl;
        std::cout << tsum << std::endl;
    }

    {
        double tsum = 0.0;
        std::vector<double> timings;
        timings.reserve(R);
        for (size_t r=0 ; r<R ; ++r) {
            ticks start = getticks();
            for (size_t i=0 ; i<nums.size() ; ++i) {
                double x = strtod(nums[i].c_str(), 0);
                tsum += x;
            }
            ticks end = getticks();
            double timed = elapsed(end, start);
            timings.push_back(timed);
        }

        std::cout << "strtod(): ";
        PrintStats(timings);
        std::cout << std::endl;
        std::cout << tsum << std::endl;
    }

    {
        double tsum = 0.0;
        std::vector<double> timings;
        timings.reserve(R);
        for (size_t r=0 ; r<R ; ++r) {
            ticks start = getticks();
            for (size_t i=0 ; i<nums.size() ; ++i) {
                double x = 0.0;
                sscanf(nums[i].c_str(), "%lf", &x);
                tsum += x;
            }
            ticks end = getticks();
            double timed = elapsed(end, start);
            timings.push_back(timed);
        }

        std::cout << "sscanf(): ";
        PrintStats(timings);
        std::cout << std::endl;
        std::cout << tsum << std::endl;
    }

    {
        double tsum = 0.0;
        std::vector<double> timings;
        timings.reserve(R);
        for (size_t r=0 ; r<R ; ++r) {
            ticks start = getticks();
            for (size_t i=0 ; i<nums.size() ; ++i) {
                double x = boost::lexical_cast<double>(nums[i]);
                tsum += x;
            }
            ticks end = getticks();
            double timed = elapsed(end, start);
            timings.push_back(timed);
        }

        std::cout << "lexical_cast: ";
        PrintStats(timings);
        std::cout << std::endl;
        std::cout << tsum << std::endl;
    }

    {
        using boost::spirit::qi::double_;
        using boost::spirit::qi::parse;
        double tsum = 0.0;
        std::vector<double> timings;
        timings.reserve(R);
        for (size_t r=0 ; r<R ; ++r) {
            ticks start = getticks();
            for (size_t i=0 ; i<nums.size() ; ++i) {
                double x = 0.0;
                char const *str = nums[i].c_str();
                parse(str, &str[nums[i].size()], double_, x);
                tsum += x;
            }
            ticks end = getticks();
            double timed = elapsed(end, start);
            timings.push_back(timed);
        }

        std::cout << "spirit qi: ";
        PrintStats(timings);
        std::cout << std::endl;
        std::cout << tsum << std::endl;
    }

    {
        double tsum = 0.0;
        std::vector<double> timings;
        timings.reserve(R);
        for (size_t r=0 ; r<R ; ++r) {
            ticks start = getticks();
            for (size_t i=0 ; i<nums.size() ; ++i) {
                std::istringstream ss(nums[i]);
                double x = 0.0;
                ss >> x;
                tsum += x;
            }
            ticks end = getticks();
            double timed = elapsed(end, start);
            timings.push_back(timed);
        }

        std::cout << "stringstream: ";
        PrintStats(timings);
        std::cout << std::endl;
        std::cout << tsum << std::endl;
    }

    {
        double tsum = 0.0;
        std::vector<double> timings;
        timings.reserve(R);
        for (size_t r=0 ; r<R ; ++r) {
            ticks start = getticks();
            std::istringstream ss;
            for (size_t i=0 ; i<nums.size() ; ++i) {
                ss.str(nums[i]);
                ss.clear();
                double x = 0.0;
                ss >> x;
                tsum += x;
            }
            ticks end = getticks();
            double timed = elapsed(end, start);
            timings.push_back(timed);
        }

        std::cout << "stringstream reused: ";
        PrintStats(timings);
        std::cout << std::endl;
        std::cout << tsum << std::endl;
    }
}
View Code
原文地址:https://www.cnblogs.com/xpvincent/p/7599757.html