производительность — не должно ли isdigit () быть быстрее в c ++?

я использую isdigit() функция в C ++, но я обнаружил, что это медленно, поэтому я реализовал свой собственный 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 реализуется битовой операцией, не должен isdigit() быть быстрее чем is_digit()?


update1

Я использую MS VS2010 с опцией по умолчанию, версия выпуска, как мне сделать, чтобы сделать isdigit() быстрее, чем is_digit() в VS?

Update2

Всем спасибо.
В режиме релиза в VS проект будет оптимизирован для скорости по умолчанию (-O2).

Все в режиме релиза.

VS2010:
is_digit: 1182 (мс)
isdigit: 3724 (мс)

VS2013:
is_digit: 0 (мс)
isdigit: 3806 (мс)

Кодовые блоки с g ++ (4.7.1) с -O3:
is_digit: 1275 (мс)
isdigit: +1331 (мс)

Итак, вот вывод:

is_digit() быстрее чем isdigit() в VS, но медленнее, чем isdigit() в г ++.

А также isdigit() в g ++ быстрее чем isdigit() в ВС

Так «VS отстой» в производительности?

1

Решение

Посмотрите на этот код (работает с g ++) с -O3

#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. Пожалуйста, обратитесь https://msdn.microsoft.com/en-us/library/19z1t1wy.aspx для оптимизации VS

1

Другие решения

В clang / llvm [компилятор по моему выбору], isdigit а также is_digit превратится в точно такой же код, так как он имеет оптимизацию для этого конкретного вызова библиотеки, чтобы перевести его в ((unsigned)(c-48) < 10u),

return c>='0' && c <='9'; также превращается в c-48 > 10 по оптимизации (как общий if x >= N && x <= M -> x-N > (M-N) преобразование, которое делает компилятор).

Таким образом, теоретически оба цикла ДОЛЖНЫ превращаться в один и тот же код (по крайней мере, с помощью компилятора, который имеет этот тип оптимизации для isdigit — не могу сказать, делает ли MSVC или нет, так как исходный код недоступен широкой публике). Я знаю, что gcc имеет похожий код для оптимизации библиотечных вызовов, но в настоящее время у меня нет gcc-источника на моей машине, и я не могу потрудиться посмотреть его [по моему опыту, это будет немного сложнее в любом случае, чтобы прочитать, чем код llvm].

Код в llvm:

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());
}

Для тех, кто не знаком с кодом LLVM: Сначала он проверяет, что вызов функции имеет правильное количество параметров и типов параметров. Если это не удается, возвращается NULL, чтобы указать «Я не могу оптимизировать это». В противном случае он строит цепочку операций, чтобы сделать if (c - '0' > 10) использование сравнения без знака, чтобы справиться с «отрицательными» значениями [которые в беззнаковых являются огромными значениями].

Было бы неправильно, если вы сделаете это:

bool isdigit(int x)
{
return image_contains_finger(imagefiles[x]);
}
[Но тогда замена библиотечных функций своей собственной версией, которая что-то делает, скорее всего, будет иметь интересные эффекты в целом!]
2

Ваша функция is_digit может быть реализована быстрее:

#define ISDIGIT(X) (((uint32_t)X - '0') < 10u)

где вы сохраняете одно сравнение. Я думаю, что это нормальный подход в gcc, но в Microsoft Visual Studio, я думаю, у вас была локализованная версия isdigit () (что для этого требует много времени при проверке локалей).

0
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector