using namespace std;
int atoi_(const char* p)
{
int result = 0;
while(*p)
{
#ifdef M
result = result*10 + *p++ - '0' ;
#else
switch(*p++)
{
case '0': result = result*10 ; break;
case '1': result = result*10 + 1 ; break;
case '2': result = result*10 + 2 ; break;
case '3': result = result*10 + 3 ; break;
case '4': result = result*10 + 4 ; break;
case '5': result = result*10 + 5 ; break;
case '6': result = result*10 + 6 ; break;
case '7': result = result*10 + 7 ; break;
case '8': result = result*10 + 8 ; break;
case '9': result = result*10 + 9 ; break;
default: break;
}
#endif
}
return result;
}
int _atoi(const char *s)
{
unsigned int i=0,n;
for(n = 0; s; i++) n = 10 * n + s - '0';
return n;
}
int main(int argc, char* argv[])
{
int loop = atoi(argv[1]);
I think that I extracted the string which cause memory allocation and slow down performance. I was using profiler and saw my code cut 0.8 seconds out of 5 seconds for the whole process instead of Convert.ToInt32. As I said before, I remove the convert to int routine from the code.
root@ubuntu:~/test# gcc -DSYS x.cc ; time ./a.out 100000000
real 0m0.438s
Your result on linux is really odd.
I am compiling with default configuration release mode.
If #define M 1
Time spent 766ms
comment out #define M 1
Time spent 782ms
use system routine atoi
Time spent 4454ms
It was running on a i3 cpu.
Here is your code I modified under visual studio
#include "stdafx.h"
//#define M 1
int
atoi_(const char* p)
{
int result = 0;
while(*p)
{
#ifdef M
result = result*10 + *p++ - '0' ;
#else
switch(*p++)
{
case '0': result = result*10 ; break;
case '1': result = result*10 + 1 ; break;
case '2': result = result*10 + 2 ; break;
case '3': result = result*10 + 3 ; break;
case '4': result = result*10 + 4 ; break;
case '5': result = result*10 + 5 ; break;
case '6': result = result*10 + 6 ; break;
case '7': result = result*10 + 7 ; break;
case '8': result = result*10 + 8 ; break;
case '9': result = result*10 + 9 ; break;
default: break;
}
#endif
}
return result;
}
int _tmain(int argc, _TCHAR* argv[])
{
int loop = _ttoi(argv[1]);
int ntime=0;
LARGE_INTEGER ntime1,ntime2;
LARGE_INTEGER freq;
QueryPerformanceFrequency(&freq);
QueryPerformanceCounter(&ntime1);
int result;
for (int i = 0; i < loop; i++)
{
// result = atoi_("1234567890");
result = atoi("1234567890");
}
1. debug的断点在case里面吧。按照MSDN,关于C#的switch的解释
“Execution of the statement list in the selected section begins with the first statement and proceeds through the statement list, typically until a jump statement is reached, such as a break, goto case, return, or throw. ”
刚才反编译了一下下面的C#代码,发现编译器(2.0和4.0结果一样)编译出的是if-else。
原code
public static int SwitchSample(string str)
{
var x = 0;
switch (str)
{
case "a":
case "b":
x = 1;
break;
case "c":
x = 2;
break;
}
return x;
}
反编译出的code(by ILSpy)
public static int SwitchSample(string str)
{
int x = 0;
if (str != null)
{
if (!(str == "a") && !(str == "b"))
{
if (str == "c")
{
x = 2;
}
}
else
{
x = 1;
}
}
return x;
}
You are right. The Convert.Int32 was written internally like "result += x - 48;".
But it's odd that this algorithm got the worst result in my investigation. Maybe my code was not good enough.
Another thing is that, I used to said "minus operation is slower than plus", that's not quite true. To computer, minus operation is actually plus operation with a reverse operation. So it should not be that slow in contrast with plus.
1. debug 的断点是在 case 里面,但不是像你理解的那样是从 case 1 开始一个一个执行到断点的。
你贴的那 ...
我想是因为switch有时是jump table的行为,有时是if-else的行为,所以MSDN为了保险起见(也免得解释具体细节),才写着从第一个开始依次执行。而且描述的很模糊。(如果是if-else行为,实际上并不是按照原C# code的顺序执行的,而是IL code的conditional顺序。对于jump table行为,则直接到matched case,不存在顺序的问题。)
“Execution of the statement list in the selected section begins with the first statement and proceeds through the statement list, typically until a jump statement is reached, such as a break, goto case, return, or throw. ”
英文写的很清楚,不是很模糊,你看这段
Execution of the statement list in the selected section
这个从句中有个 in the selected section 这个地方限制了前面讲的 Execution of the statement 是在 the selected section 里面的,即 matched case 里面的,而不是你理解的从第一个 case 开始顺序执行。
我附上中文版本 MSDN 官方翻译的这段话,以帮助你理解
语句体从选定的语句开始执行,直到 break 将控制传递到 case 体以外。在每一个 case 块(包括上一个块,不论它是 case 语句还是 default 语句)的后面,都必须有一个跳转语句(如 break)。但有一个例外,(与 C++ switch 语句不同)C# 不支持从一个 case 标签显式贯穿到另一个 case 标签。这个例外是当 case 语句中没有代码时。