C++ 07 Feb 2010 15:41:15
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.42 | Percentage |
|---|---|
| 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.42 | Percentage |
|---|---|
| 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.42 | Percentage |
|---|---|
| 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% |

on 10 Mar 2010 at 16:36:32 1.Sumant said …
Quite interesting! The performance results on g++ (4.4.3) hold as they are shown only when optimizations are turned on. With the increasing level of optimizations (-O1, -O2, -O3), performance improves.
on 10 Mar 2010 at 23:45:39 2.indranil banerjee said …
Interesting. Surprised to see that lexical_cast performed better than stringstream, I thought the former was implemented using the latter?
These results are quite contrary to the tests Sutter published back in 2001 http://www.gotw.ca/publications/mill19.htm. In those tests sprintf was the fastest, followed by strstream, stringstream & lexical_cast trailing. Have things changed so much?
on 11 Mar 2010 at 11:04:34 3.Arzar said …
I’m quite surprised to see lexical_cast performing this good too.
Most of all, if you define BOOST_LEXICAL_CAST_ASSUME_C_LOCALE the performance of lexical_cast increase even more. With MSCV10, I get ~30% instead of 70% !
(for reference, I get ~15% with itoa)
on 11 Mar 2010 at 11:36:09 4.Tino Didriksen said …
It has since been specialized for the basic integer and floating point types: http://www.boost.org/doc/libs/release/boost/lexical_cast.hpp (search for lcast_put_unsigned and below).
But for all other conversions, it is indeed dog slow. Just see http://tinodidriksen.com/2010/02/16/cpp-convert-string-to-int-speed/ where it trails by a huge margin.
on 12 Mar 2010 at 04:48:23 5.Jeff said …
You should try against ‘fast format’ too, for completeness – Matt Wilson’s no slouch.
http://www.fastformat.org/performance.html