在c ++中,难道不是digit()更快吗?

时间:2015-02-10 06:13:27

标签: c++ performance digit

我在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糟透了”的表现?

3 个答案:

答案 0 :(得分:2)

在clang / llvm [我选择的编译器]中,isdigitis_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()的本地化版本(因此需要很长时间检查语言环境)。