я использую 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 отстой» в производительности?
Посмотрите на этот код (работает с 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
В 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]);
}
[Но тогда замена библиотечных функций своей собственной версией, которая что-то делает, скорее всего, будет иметь интересные эффекты в целом!]
Ваша функция is_digit может быть реализована быстрее:
#define ISDIGIT(X) (((uint32_t)X - '0') < 10u)
где вы сохраняете одно сравнение. Я думаю, что это нормальный подход в gcc, но в Microsoft Visual Studio, я думаю, у вас была локализованная версия isdigit () (что для этого требует много времени при проверке локалей).