C++ 16 Feb 2010 19:58:03

C++ Convert String to Int Speed

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

(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 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, GNU g++ 4.4.1, and LLVM clang++ from svn.

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.

Windows: MSVC++ 2010 Express

  • Compiler: MSVC++ 2010 Express _SECURE_SCL=0
  • Arch: Windows 7 64 bit, 1.83GHz Core2Duo, 4 GiB RAM
VC++ 2010TicksRelative Factor
atoi()124143031.00
atol()123731191.00
strtol()117096430.94
lexical_cast59605024648.01
stringstream66723014653.75
stringstream reused36572222529.46
naive23079210.19

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.1TicksRelative Factor
atoi()79169921.00
atol()79535201.00
strtol()79461121.00
lexical_cast9209956811.63
stringstream18864843223.83
stringstream reused431374565.45
naive26889760.34

Linux: LLVM clang++ 1.5 (trunk 101368)

clang++ 1.5 (trunk 101368)TicksRelative Factor
atoi()80263041.00
atol()78234560.97
strtol()75976960.95
lexical_cast9425075211.74
stringstream18280075222.78
stringstream reused432343205.39
naive29515040.37
Share

7 Responses to “C++ Convert String to Int Speed”

  1. on 20 Mar 2010 at 03:47:49 1.Alex said …

    It’s funny.
    But why boost::lexical_cast is so slow?

  2. on 20 Mar 2010 at 10:28:03 2.Tino Didriksen said …

    boost::lexical_cast is so slow because it wraps around a std::stringstream and performs many extra checks on top of that, such as ensuring that the entire input was used for conversion.

  3. on 09 Mar 2011 at 13:18:58 3.Tomalak Geret'kal said …

    Does MSVS2010 use a C++0x stdlib by default?

  4. on 09 Mar 2011 at 13:57:42 4.Tino Didriksen said …

    Yes it does.

  5. on 20 Apr 2011 at 01:40:45 5.graphitemaster said …

    the naive method is the fastest – always is.

  6. on 13 Jul 2011 at 21:30:04 6.phax said …

    static uint64_t decdigits[100] =
    {
    0ll,0ll,0ll,0ll,0ll,0ll,0ll,0ll,0ll,0,
    1ll,10ll,100ll,1000ll,10000ll,100000ll,1000000ll,10000000ll,100000000ll,1000000000ll,
    2ll,20ll,200ll,2000ll,20000ll,200000ll,2000000ll,20000000ll,200000000ll,2000000000ll,
    3ll,30ll,300ll,3000ll,30000ll,300000ll,3000000ll,30000000ll,300000000ll,3000000000ll,
    4ll,40ll,400ll,4000ll,40000ll,400000ll,4000000ll,40000000ll,400000000ll,400000000ll,
    5ll,50ll,500ll,5000ll,50000ll,500000ll,5000000ll,50000000ll,500000000ll,5000000000ll,
    6ll,60ll,600ll,6000ll,60000ll,600000ll,6000000ll,60000000ll,600000000ll,6000000000ll,
    7ll,70ll,700ll,7000ll,70000ll,700000ll,7000000ll,70000000ll,700000000ll,7000000000ll,
    8ll,80ll,800ll,8000ll,80000ll,800000ll,8000000ll,80000000ll,800000000ll,8000000000ll,
    9ll,90ll,900ll,9000ll,90000ll,900000ll,9000000ll,90000000ll,900000000ll,9000000000ll
    };

    long long int naive2(const char * __restrict__ p)
    {
    bool neg((*p==’-')?1:0);
    register int64_t num(0);
    register size_t pos(strlen(p+neg)-1);

    neg && ++p;

    while (*p)
    num+= decdigits[(*p++ - '0')* 10 + pos--];
    return (neg?-num:num);
    }

  7. on 14 Jul 2011 at 15:06:49 7.phax said …

    Another naive() in asm though, only tested on Linux g++ 4.4.3, not sure if VC++ supports this semantics for inlining asm.

    long long int __inline__ naive2(const char * p)
    {
    int result(0);
    int neg(0);

    // result -> ecx, p -> ebx
    asm (
    “movl %0, %%ecx\t\n”
    “movl %2, %%ebx\t\n”
    “movl $0, %%edx\t\n”
    “movb (%%ebx),%%dl\t\n”
    “subb $45, %%dl\t\n”
    “jnz loop1\t\n”
    “movl $1, %1\t\n”
    “incl %%ebx\t\n”
    “loop1:\t\n”
    “movl $0, %%edx\t\n”
    “movb (%%ebx), %%dl\t\n”
    “testb %%dl,%%dl\t\n”
    “jz exitloop1\t\n”
    “subb $48, %%dl\t\n”
    “movl %%ecx, %%eax\t\n”
    “shll $3,%%ecx\t\n”
    “addl %%eax, %%ecx\t\n”
    “addl %%eax, %%ecx\t\n”
    “addl %%edx,%%ecx\t\n”
    “incl %%ebx\t\n”
    “jmp loop1\t\n”
    “exitloop1:\t\n”
    “movl %%ecx, %0\t\n”
    :
    “=r” (result), “=m” (neg)
    :
    “r”(p),”0″(result), “m” (neg)
    : “%ebx”, “%eax”, “%ecx”, “%edx”
    );
    return neg?-result:result;
    }

Subscribe to the comments through RSS Feed

Leave a Reply

*
To prove you're a person (not a spam script), type the security word shown in the picture. Click on the picture to hear an audio file of the word.
Anti-spam image