我在c ++中使用isdigit()
函数,但我发现它很慢,所以我实现了自己的is_digit()
,请参阅下面的代码:
#include<iostream>
#include<cctype>
#include<ctime>
using namespace std;
static inline bool is_digit(char c)
{
return c>='0'&&c<='9';
}
int main()
{
char c='8';
time_t t1=clock(),t2,t3;
for(int i=0;i<1e9;i++)
is_digit(c);
t2=clock();
for(int i=0;i<1e9;i++)
isdigit(c);
t3=clock();
cout<<"is_digit:"<<(t2-t1)/CLOCKS_PER_SEC<<"\nisdigit:"<<(t3-t2)/CLOCKS_PER_SEC<<endl;
return 0;
}
运行后,is_digit()
仅用了1秒钟(1161毫秒),但是isdigit()
用了4秒钟(3674毫秒),我知道isdigit
是通过位操作实现的,不应该{ {1}}要比isdigit()
快吗?
UPDATE1
我使用MS VS2010默认选项,发布版本,如何让is_digit()
比VS中的isdigit()
更快?
UPDATE2
感谢大家。 在VS中处于释放模式时,项目将针对速度默认值(-O2)进行优化。
全部处于发布模式。
VS2010: is_digit:1182(毫秒) ISDIGIT:3724(ms)的
VS2013: is_digit:0(ms)的 ISDIGIT:3806(ms)的
带有-O3的g ++(4.7.1)的代码块: is_digit:1275(毫秒) ISDIGIT:1331(ms)的
所以这是结论:
is_digit()
在VS中比is_digit()
快,但在g ++中慢于isdigit()
。
g ++中的isdigit()
比VS中的isdigit()
快。
所以“VS糟透了”的表现?
答案 0 :(得分:2)
在clang / llvm [我选择的编译器]中,isdigit
和is_digit
将变成完全相同的代码,因为它对该特定库调用进行了优化,以将其转换为{{1 }}。
((unsigned)(c-48) < 10u)
也会通过优化变为return c>='0' && c <='9';
(作为编译器执行的通用c-48 > 10
- &gt; if x >= N && x <= M
转换)。
所以,从理论上讲,两个循环应该变成相同的代码(至少对于x-N > (M-N)
具有这种优化类型的编译器 - 无论MSVC是否成功,我都不能说,作为一般公众无法获得源代码。我知道gcc有类似的代码来优化库调用,但我目前在我的机器上没有gcc源代码,我也不会费心去查找[根据我的经验,它会有点困难阅读比llvm代码,反正]。
llvm中的代码:
isdigit
对于那些不熟悉LLVM代码的人:它首先检查函数调用是否具有正确数量的参数和参数类型。如果失败,则返回NULL以指示“我无法优化此”。否则,它构建操作链以使用无符号比较来执行Value *LibCallSimplifier::optimizeIsDigit(CallInst *CI, IRBuilder<> &B) {
Function *Callee = CI->getCalledFunction();
FunctionType *FT = Callee->getFunctionType();
// We require integer(i32)
if (FT->getNumParams() != 1 || !FT->getReturnType()->isIntegerTy() ||
!FT->getParamType(0)->isIntegerTy(32))
return nullptr;
// isdigit(c) -> (c-'0') <u 10
Value *Op = CI->getArgOperand(0);
Op = B.CreateSub(Op, B.getInt32('0'), "isdigittmp");
Op = B.CreateICmpULT(Op, B.getInt32(10), "isdigit");
return B.CreateZExt(Op, CI->getType());
}
以处理“负”值[无符号值是巨大的值]。
如果你这样做会出错:
if (c - '0' > 10)
[但随后用您自己的版本替换库函数,通常会产生一些有趣的效果!]
答案 1 :(得分:1)
使用-O3
查看此代码(与g ++一起使用)#include<iostream>
#include<cctype>
#include<ctime>
#include <time.h>
#include <sys/time.h>
using namespace std;
static inline bool is_digit(char c)
{
return c>='0'&&c<='9';
}
int main()
{
char c='8';
struct timeval tvSt, tvEn;
time_t t1=clock(),t2,t3;
gettimeofday(&tvSt, 0);
for(int i=0;i<1e9;i++)
is_digit(c);
gettimeofday(&tvEn, 0);
cout << "is_digit:" << (tvEn.tv_sec - tvSt.tv_sec)*1000000 + (tvEn.tv_usec - tvSt.tv_usec) << " us"<< endl;
gettimeofday(&tvSt, 0);
for(int i=0;i<1e9;i++)
isdigit(c);
gettimeofday(&tvEn, 0);
cout << "isdigit:" << (tvEn.tv_sec - tvSt.tv_sec)*1000000 + (tvEn.tv_usec - tvSt.tv_usec) << " us"<< endl;
return 0;
}
<强>结果:强>
is_digit:1610771 us
isdigit:1055976 us
所以,C ++的实现比你好 通常情况下,当你衡量表现时,用秒来做这件事并不是一个好主意。至少考虑微秒级别。
我不确定VS.请找出微秒级时钟和测量。
PS。有关VS优化的信息,请参阅https://msdn.microsoft.com/en-us/library/19z1t1wy.aspx
答案 2 :(得分:0)
您的函数is_digit可以通过以下方式更快地实现:
#define ISDIGIT(X) (((uint32_t)X - '0') < 10u)
保存一个比较的地方。我认为,这是gcc中的正常approch,但在Microsoft Visual Studio中,我猜你有一个isdigit()的本地化版本(因此需要很长时间检查语言环境)。