Мне стало любопытно, и я провел небольшой тест, чтобы определить разницу в производительности между примитивными типами, такими как int
или float
, и пользовательскими типами.
Я создал класс шаблона Var
, создал несколько встроенных арифметических операторов. Тест состоял из зацикливания этого цикла как для примитивного, так и для Var
векторов:
for (unsigned i = 0; i < 1000; ++i) {
in1[i] = i;
in2[i] = -i;
out[i] = (i % 2) ? in1[i] + in2[i] : in2[i] - in1[i];
}
Я был очень удивлен результатами, оказалось, что мой класс Var
большую часть времени работает быстрее, с int в среднем этот цикл занимает примерно на 5700 нс меньше с классом. Из 3000 запусков int оказался быстрее в 11 раз, а Var
— в 2989 раз. Аналогичные результаты с float
, где Var
на 15100 нс быстрее, чем floatin 2991 прогонов.
Разве примитивные типы не должны быть быстрее?
Редактировать: компилятор - это довольно древний mingw 4.4.0, параметры сборки - значения по умолчанию для QtCreator, без оптимизации:
qmake call: qmake.exe C:\...\untitled15.pro -r -spec win32-g++ "CONFIG+=release"
ОК, публикую полный исходный код, платформа 64-битная Win7, 4 ГБ DDR2-800, Core2Duo@3Ghz
#include <QTextStream>
#include <QVector>
#include <QElapsedTimer>
template<typename T>
class Var{
public:
Var() {}
Var(T val) : var(val) {}
inline T operator+(Var& other)
{
return var + other.value();
}
inline T operator-(Var& other)
{
return var - other.value();
}
inline T operator+(T& other)
{
return var + other;
}
inline T operator-(T& other)
{
return var - other;
}
inline void operator=(T& other)
{
var = other;
}
inline T& value()
{
return var;
}
private:
T var;
};
int main()
{
QTextStream cout(stdout);
QElapsedTimer timer;
unsigned count = 1000000;
QVector<double> pin1(count), pin2(count), pout(count);
QVector<Var<double> > vin1(count), vin2(count), vout(count);
unsigned t1, t2, pAcc = 0, vAcc = 0, repeat = 10, pcount = 0, vcount = 0, ecount = 0;
for (int cc = 0; cc < 5; ++cc)
{
for (unsigned c = 0; c < repeat; ++c)
{
timer.restart();
for (unsigned i = 0; i < count; ++i)
{
pin1[i] = i;
pin2[i] = -i;
pout[i] = (i % 2) ? pin1[i] + pin2[i] : pin2[i] - pin1[i];
}
t1 = timer.nsecsElapsed();
cout << t1 << endl;
timer.restart();
for (unsigned i = 0; i < count; ++i)
{
vin1[i] = i;
vin2[i] = -i;
vout[i] = (i % 2) ? vin1[i] + vin2[i] : vin2[i] - vin1[i];
}
t2 = timer.nsecsElapsed();
cout << t2 << endl;;
pAcc += t1;
vAcc += t2;
}
pAcc /= repeat;
vAcc /= repeat;
if (pAcc < vAcc) {
cout << "primitive was faster" << endl;
pcount++;
}
else if (pAcc > vAcc) {
cout << "var was faster" << endl;
vcount++;
}
else {
cout << "amazingly, both are equally fast" << endl;
ecount++;
}
cout << "Average for primitive type is " << pAcc << ", average for Var is " << vAcc << endl;
}
cout << "int was faster " << pcount << " times, var was faster " << vcount << " times, equal " << ecount << " times, " << pcount + vcount + ecount << " times ran total" << endl;
}
Относительно, с числами с плавающей запятой класс Var на 6-7% быстрее, чем с числами с плавающей запятой, с целыми примерно на 3%.
Я также провел тест с длиной вектора 10 000 000 вместо исходных 1000, и результаты по-прежнему согласуются и в пользу класса.
int
, а затем версию класса в рамках одного прогона? Это могло абсолютно исказить результаты, если что-то было кэшировано. - person Mark B   schedule 06.06.2012float
все промежуточные значения вычисляются путем преобразования их вdouble
.int
, однако, является типом данных для всех целочисленных типов, так что это оптимально (по сравнению с любым изchar
,long
и т. д.). Попробуйте сdouble
и сообщите нам о результатах. - person dirkgently   schedule 06.06.2012