Category ArchiveC++



C++ 16 Feb 2010 07:58 pm

C++ Convert String to Int Speed

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

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

The tested methods are:

  • atoi()
  • atol()
  • strtol()
  • std::stringstream
  • std::stringstream, reusing the object
  • boost::lexical_cast<int>()
  • a hand-written naive loop

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

The compilers are Microsoft Visual C++ 2010 Express as VC10 with _SECURE_SCL disabled, and GNU g++ 4.3.2.

Tests were run for converting 100000 string containing integers in the range -50000 to 50000. The result for atoi() is set as the baseline 100% and the other numbers is time spent relative to that. The naive loop wins by a large margin.

VC++ 2010
atoi()100.00%
atol()96.73%
strtol()93.94%
stringstream5164.50%
stringstream reused2817.94%
boost::lexical_cast4471.66%
naive loop18.43%
g++ 4.3.2
atoi()100.00%
atol()100.47%
strtol()97.00%
stringstream2040.35%
stringstream reused482.86%
boost::lexical_cast1004.41%
naive loop37.39%

C++ 07 Feb 2010 03:41 pm

C++ Convert Int to String Speed

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

(Updated 2010-03-05 to compare speeds of reusing the string object versus not, and to add strstream and boost::spirit::karma tests.)

A performance benchmark of which method is faster of converting an integer to an std::string. The goal is ending up with an std::string representation of the input integer.

The tested methods are:

  • sprintf() into a char[] buffer, then std::string(buffer)
  • snprintf() into a char[] buffer, then std::string(buffer)
  • sprintf() into &std::string[0], and .resize() to fit
  • snprintf() into &std::string[0], and .resize() to fit
  • output to a std::stringstream, then std::string = stream.str()
  • as above, but reusing the stringstream object
  • std::strstream(&string[0]) then .resize(stream.pcount())
  • std::string = boost::lexical_cast<std::string>()
  • Boost.Spirit.Karma generate into a char[] buffer, then std::string(buffer)

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

The compilers are Microsoft Visual C++ 2010 Express as VC10 with _SECURE_SCL disabled, GNU g++ 4.3.2, and clang++ from svn.

Tests were run for converting 100000 integers in the range -50000 to 50000. The result for sprintf() is set as the baseline 100% and the other numbers is time spent relative to that.

Boost.Spirit.Karma is by far the fastest. It is also worth noting that reusing the string object makes the boost::lexical_cast solution slower, presumably because it ruins some optimization opportunities, so that is a case for checking whether reusing your objects really is faster…

VC++ 2010, Boost 1.42Percentage
sprintf char[] (reuse string)100.00%
sprintf char[] (new string)100.39%
snprintf char[] (reuse string)99.39%
sprintf &string[0] (reuse string)103.22%
snprintf &string[0] (reuse string)103.85%
stringstream (new stream, reuse string)502.88%
stringstream (new stream, new string)507.08%
stringstream (reuse stream, reuse string)278.56%
stringstream (reuse stream, new string)280.29%
strstream (reuse stream, internal buffer)611.35%
strstream (reuse stream, string buffer)621.25%
lexical_cast (reuse string)72.99%
lexical_cast (new string)69.72%
karma (reuse string)9.52%
karma (new string)10.17%
Fedora g++ 4.3.2, Boost 1.42Percentage
sprintf char[] (reuse string)100.00%
sprintf char[] (new string)124.93%
snprintf char[] (reuse string)99.21%
sprintf &string[0] (reuse string)103.14%
snprintf &string[0] (reuse string)105.37%
stringstream (new stream, reuse string)465.73%
stringstream (new stream, new string)471.35%
stringstream (reuse stream, reuse string)137.44%
stringstream (reuse stream, new string)131.40%
strstream (new stream, internal buffer)463.57%
strstream (reuse stream, string buffer)285.54%
lexical_cast (reuse string)96.26%
lexical_cast (new string)89.18%
karma (reuse string)32.79%
karma (new string)61.48%

The clang++ results are directly comparable with the g++ results; run on the same machine, and the sprintf() results deviate a mere 0.07%. clang++ could not compile the karma test, so that has been omitted.

clang++ 1.1 (trunk 97850), Boost 1.42Percentage
sprintf char[] (reuse string)100.00%
sprintf char[] (new string)129.02%
snprintf char[] (reuse string)99.57%
sprintf &string[0] (reuse string)102.61%
snprintf &string[0] (reuse string)103.92%
stringstream (new stream, reuse string)493.95%
stringstream (new stream, new string)499.09%
stringstream (reuse stream, reuse string)140.36%
stringstream (reuse stream, new string)133.43%
strstream (new stream, reuse string)506.13%
strstream (reuse stream, reuse string)279.85%
lexical_cast (reuse string)101.45%
lexical_cast (new string)95.87%

C++ 02 Feb 2010 04:38 pm

C++ Find Unique Elements Speed

A performance benchmark of which method is faster of finding all unique elements of a vector. The goal is having an ordered container with just the unique elements, where the tested methods are std::sort()+std::unique()+erase(), versus inserting into a separate std::set, versus inserting into std::unordered_set and then into std::set, and finally inserting into boost::unordered_set and then into std::set.

Source for the integer version is speed-find-unique-int.cpp with cycle.h.

The compilers are Microsoft Visual C++ 2010 Express as VC10 with _SECURE_SCL disabled, and GNU g++ 4.3.2.

Tests were run with 10000, 100000, 1000000, and 10000000 elements, of which 1000 are unique. For my own amusement I also tried 10000 and 32767 unique elements, but relative speeds were roughly the same.

The set.insert() column describes how much time was spent in relation to the same operation with sort()+unique()+erase(). For integers, this number is above 100% for all tests, meaning it is slower to use std::set.

<int>sort()+unique()set.insert()hash+setboost hash+set
VC10 n=10k100.00%273.51%376.30%97.39%
VC10 n=100k100.00%287.09%274.24%29.41%
VC10 n=1m100.00%335.19%329.24%25.60%
VC10 n=10m100.00%343.77%350.25%20.63%
-
g++ 4.3.2 n=10k100.00%160.28%47.49%55.51%
g++ 4.3.2 n=100k100.00%153.75%22.54%28.49%
g++ 4.3.2 n=1m100.00%147.02%27.61%36.09%
g++ 4.3.2 n=10m100.00%138.61%29.63%35.38%

And then there is the std::string version, source speed-find-unique-string.cpp with cycle.h.

For VC10, all is as expected from the integer results. However, for g++ it is considerably faster to use std::set.

I tried a test for g++ where I force a full string copy to get around g++’s copy-on-write implementation, but it didn’t change much.

<string>sort()+unique()set.insert()hash+setboost hash+set
VC10 n=10k100.00%140.72%91.90%33.12%
VC10 n=100k100.00%163.90%106.33%20.82%
VC10 n=1m100.00%153.36%101.79%16.35%
VC10 n=10m100.00%158.99%107.24%16.62%
-
g++ 4.3.2 n=10k100.00%62.53%19.44%22.69%
g++ 4.3.2 n=100k100.00%61.05%12.06%11.88%
g++ 4.3.2 n=1m100.00%29.23%5.43%3.99%
g++ 4.3.2 n=10m100.00%18.55%3.64%2.54%

C++ 01 Feb 2010 03:32 pm

Snippet: Dynamic Box of Strings

http://tinodidriksen.com/uploads/code/cpp/dynamic-string-box.cpp

#include <iostream>
#include <algorithm>
#include <string>
#include <vector>

int main() {
    std::vector<std::string> strs;
    strs.push_back("Hello World!");
    strs.push_back("This is a text line.");
    strs.push_back("Shorter line.");

    size_t maxl = 0;
    for (size_t i = 0 ; i<strs.size() ; ++i) {
        maxl = std::max(maxl, strs[i].length());
    }

    std::cout << std::string(maxl+4, '*') << std::endl;
    for (size_t i = 0 ; i<strs.size() ; ++i) {
        std::cout << "* "
            << strs[i]
            << std::string(maxl-strs[i].length()+1, ' ')
            << "*" << std::endl;
    }
    std::cout << std::string(maxl+4, '*') << std::endl;
}

C++ 31 Jan 2010 11:46 pm

Snippet: Sort Unique Vector

http://tinodidriksen.com/uploads/code/cpp/sort-unique-vector.cpp

#include <vector>
#include <iostream>
#include <algorithm>

int main() {
    std::vector<int> vec1;
    vec1.push_back(1);
    vec1.push_back(2);
    vec1.push_back(3);
    vec1.push_back(1);
    vec1.push_back(2);
    vec1.push_back(3);
    vec1.push_back(1);

    std::sort(vec1.begin(), vec1.end());
    vec1.erase(std::unique(vec1.begin(), vec1.end()), vec1.end());

    std::cout << vec1.size() << std::endl;
    std::cout << vec1[0] << vec1[1] << vec1[2] << std::endl;
}

Next Page »