C++ most efficient way to convert string to int (faster than atoi)

后端 未结 10 962
遥遥无期
遥遥无期 2020-12-04 17:04

As mentioned in the title, I\'m looking for something that can give me more performance than atoi. Presently, the fastest way I know is

atoi(mystring.c_str(         


        
10条回答
  •  粉色の甜心
    2020-12-04 17:29

    Here is mine. Atoi is the fastest I could come up with. I compiled with msvc 2010 so it might be possible to combine both templates. In msvc 2010, when I combined templates it made the case where you provide a cb argument slower.

    Atoi handles nearly all the special atoi cases, and is as fast or faster than this:

    int val = 0;
    while( *str ) 
        val = val*10 + (*str++ - '0');
    

    Here is the code:

    #define EQ1(a,a1) (BYTE(a) == BYTE(a1))
    #define EQ1(a,a1,a2) (BYTE(a) == BYTE(a1) && EQ1(a,a2))
    #define EQ1(a,a1,a2,a3) (BYTE(a) == BYTE(a1) && EQ1(a,a2,a3))
    
    // Atoi is 4x faster than atoi.  There is also an overload that takes a cb argument.
    template  
    T Atoi(LPCSTR sz) {
        T n = 0;
        bool fNeg = false;  // for unsigned T, this is removed by optimizer
        const BYTE* p = (const BYTE*)sz;
        BYTE ch;
        // test for most exceptions in the leading chars.  Most of the time
        // this test is skipped.  Note we skip over leading zeros to avoid the 
        // useless math in the second loop.  We expect leading 0 to be the most 
        // likely case, so we test it first, however the cpu might reorder that.
        for ( ; (ch=*p-'1') >= 9 ; ++p) { // unsigned trick for range compare
          // ignore leading 0's, spaces, and '+'
          if (EQ1(ch, '0'-'1', ' '-'1', '+'-'1'))
            continue;
          // for unsigned T this is removed by optimizer
          if (!((T)-1 > 0) && ch==BYTE('-'-'1')) {
            fNeg = !fNeg;
            continue;
          }
          // atoi ignores these.  Remove this code for a small perf increase.
          if (BYTE(*p-9) > 4)  // \t, \n, 11, 12, \r. unsigned trick for range compare
            break;
        }
        // deal with rest of digits, stop loop on non digit.
        for ( ; (ch=*p-'0') <= 9 ; ++p) // unsigned trick for range compare
          n = n*10 + ch; 
        // for unsigned T, (fNeg) test is removed by optimizer
        return (fNeg) ? -n : n;
    }
    
    // you could go with a single template that took a cb argument, but I could not
    // get the optimizer to create good code when both the cb and !cb case were combined.
    // above code contains the comments.
    template 
    T Atoi(LPCSTR sz, BYTE cb) {
        T n = 0;
        bool fNeg = false; 
        const BYTE* p = (const BYTE*)sz;
        const BYTE* p1 = p + cb;
        BYTE ch;
        for ( ; p= 9 ; ++p) {
          if (EQ1(ch,BYTE('0'-'1'),BYTE(' '-'1'),BYTE('+'-'1')))
            continue;
          if (!((T)-1 > 0) && ch == BYTE('-'-'1')) {
            fNeg = !fNeg;
            continue;
          }
          if (BYTE(*p-9) > 4)  // \t, \n, 11, 12, \r
            break;
        }
        for ( ; p

提交回复
热议问题