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.)
(Updated 2010-04-15: Re-run with g++ 4.4.1 and VC++ 2010 Express; updated tables to show both ticks and relative factor, instead of just percentage of baseline.)
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.4.1, 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…
Windows: MSVC++ 2010 Express
- Compiler: MSVC++ 2010 Express _SECURE_SCL=0
- Arch: Windows 7 64 bit, 1.83GHz Core2Duo, 4 GiB RAM
| VC++ 2010 | Ticks | Relative Factor |
|---|---|---|
| sprintf char[] (reuse string) | 106785239 | 1.00 |
| sprintf char[] (new string) | 107044355 | 1.00 |
| snprintf char[] (reuse string) | 106075442 | 0.99 |
| sprintf &string[0] (reuse string) | 109167377 | 1.02 |
| snprintf &string[0] (reuse string) | 109986019 | 1.03 |
| stringstream (new stream, reuse string) | 676320315 | 6.33 |
| stringstream (new stream, new string) | 663385943 | 6.21 |
| stringstream (reuse stream, reuse string) | 370421260 | 3.47 |
| stringstream (reuse stream, new string) | 365431770 | 3.42 |
| strstream (new stream, reuse string) | 829640218 | 7.77 |
| strstream (reuse stream, reuse string) | 619327071 | 5.80 |
| lexical_cast (reuse string) | 95274179 | 0.89 |
| lexical_cast (new string) | 88213686 | 0.83 |
| karma (reuse string) | 11384186 | 0.11 |
| karma (new string) | 11326623 | 0.11 |
Linux: GNU g++ 4.4.1
- Compiler: GNU g++ 4.4.1 -std=c++0x -O3
- Arch: Linux 2.6.27 x86_64, 2.66GHz Xeon, 8 GiB RAM
| g++ 4.4.1 | Ticks | Relative Factor |
|---|---|---|
| sprintf char[] (reuse string) | 36985120 | 1.00 |
| sprintf char[] (new string) | 46394288 | 1.25 |
| snprintf char[] (reuse string) | 37010400 | 1.00 |
| sprintf &string[0] (reuse string) | 37815120 | 1.02 |
| snprintf &string[0] (reuse string) | 38379488 | 1.04 |
| stringstream (new stream, reuse string) | 188474672 | 5.10 |
| stringstream (new stream, new string) | 188673472 | 5.10 |
| stringstream (reuse stream, reuse string) | 50254256 | 1.36 |
| stringstream (reuse stream, new string) | 47276768 | 1.28 |
| strstream (new stream, reuse string) | 187579824 | 5.07 |
| strstream (reuse stream, reuse string) | 118805664 | 3.21 |
| lexical_cast (reuse string) | 34774944 | 0.94 |
| lexical_cast (new string) | 32984960 | 0.89 |
| karma (reuse string) | 12173344 | 0.33 |
| karma (new string) | 23319072 | 0.63 |
Linux: LLVM clang++
- Compiler: clang++ 1.5 (trunk 101368) -std=c++0x -O3
- Arch: Linux 2.6.27 x86_64, 2.66GHz Xeon, 8 GiB RAM
- The karma test could not compile with clang++, so it has been omitted.
| clang++ 1.5 (trunk 101368) | Ticks | Relative Factor |
|---|---|---|
| sprintf char[] (reuse string) | 36867376 | 1.00 |
| sprintf char[] (new string) | 47885136 | 1.30 |
| snprintf char[] (reuse string) | 37241056 | 1.01 |
| sprintf &string[0] (reuse string) | 37544640 | 1.02 |
| snprintf &string[0] (reuse string) | 37497568 | 1.02 |
| stringstream (new stream, reuse string) | 195807968 | 5.31 |
| stringstream (new stream, new string) | 194174080 | 5.27 |
| stringstream (reuse stream, reuse string) | 50532560 | 1.37 |
| stringstream (reuse stream, new string) | 47964352 | 1.30 |
| strstream (new stream, reuse string) | 193010416 | 5.24 |
| strstream (reuse stream, reuse string) | 121253440 | 3.29 |
| lexical_cast (reuse string) | 36813376 | 1.00 |
| lexical_cast (new string) | 34610368 | 0.94 |

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
on 25 Mar 2010 at 14:54:46 6.Jeff said …
How about Qt? They generally have things optimized pretty well.
on 20 Jun 2010 at 23:39:19 7.Arash Partow said …
Have you considered including StrTk in your listings?
The tests used in that library are a little more extensive.
http://www.codeproject.com/KB/recipes/Tokenizer.aspx