Я проверяю разницу между двумя реализациями градиентного спуска, я предполагал, что после оптимизации компилятора обе версии алгоритма будут эквивалентны.Почему рекурсивная версия функции будет быстрее, чем итеративная в C?
Для моего удивления рекурсивная версия была значительно быстрее. Я не отбрасываю фактический дефект ни на одну из версий, ни даже на то, как я измеряю время. Можете ли вы, ребята, рассказать мне, пожалуйста?
Это мой код:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <stdint.h>
double f(double x)
{
return 2*x;
}
double descgrad(double xo, double xnew, double eps, double precision)
{
// printf("step ... x:%f Xp:%f, delta:%f\n",xo,xnew,fabs(xnew - xo));
if (fabs(xnew - xo) < precision)
{
return xnew;
}
else
{
descgrad(xnew, xnew - eps*f(xnew), eps, precision);
}
}
double descgraditer(double xo, double xnew, double eps, double precision)
{
double Xo = xo;
double Xn = xnew;
while(fabs(Xn-Xo) > precision)
{
//printf("step ... x:%f Xp:%f, delta:%f\n",Xo,Xn,fabs(Xn - Xo));
Xo = Xn;
Xn = Xo - eps * f(Xo);
}
return Xn;
}
int64_t timespecDiff(struct timespec *timeA_p, struct timespec *timeB_p)
{
return ((timeA_p->tv_sec * 1000000000) + timeA_p->tv_nsec) -
((timeB_p->tv_sec * 1000000000) + timeB_p->tv_nsec);
}
int main()
{
struct timespec s1, e1, s2, e2;
clock_gettime(CLOCK_MONOTONIC, &s1);
printf("Minimum : %f\n",descgraditer(100,99,0.01,0.00001));
clock_gettime(CLOCK_MONOTONIC, &e1);
clock_gettime(CLOCK_MONOTONIC, &s2);
printf("Minimum : %f\n",descgrad(100,99,0.01,0.00001));
clock_gettime(CLOCK_MONOTONIC, &e2);
uint64_t dif1 = timespecDiff(&e1,&s1)/1000;
uint64_t dif2 = timespecDiff(&e2,&s2)/1000;
printf("time_iter:%llu ms, time_rec:%llu ms, ratio (dif1/dif2) :%g\n", dif1,dif2, ((double) ((double)dif1/(double)dif2)));
printf("End. \n");
}
Я компиляции с GCC 4.5.2 на Ubuntu 11.04 со следующими параметрами: НКУ grad.c -O3 -lrt -о дг
Выход мой код:
Minimum : 0.000487
Minimum : 0.000487
time_iter:127 ms, time_rec:19 ms, ratio (dif1/dif2) :6.68421
End.
я прочитал нить, которая также спросить о рекурсивной версии алгоритма был быстрее, чем повторяющийся. Объяснение в том, что, будучи рекурсивной версией, использующей стек, а другая версия с использованием некоторых векторов, доступ к куче замедлял итеративную версию. Но в этом случае (в лучшем смысле) я просто использую стек в обоих случаях.
Я что-то упустил? Что-нибудь очевидное, что я не вижу? Мой способ измерить время не так? Какие-нибудь идеи?
EDIT: Тайна решена в комментарии. Как сказал @TonyK, инициализация printf замедляла первое выполнение. Извините, что я пропустил эту очевидную вещь.
BTW, код компилируется сразу же без предупреждений. Я не думаю, что «возвращение descgrad (..» необходимо, так как условие остановки происходит до того
Все «почему это быстрее?» вопросы должны сопровождаться списком ассемблера, выводимым из вашего компилятора. –
Где находится элемент возврата для 'descgrad' для случая, когда выражение' if' ложно? Этот код не должен компилироваться. –
@ user112358132134: Нах, он должен просто компилироваться с предупреждением, нет? –