Почему рекурсивная версия функции будет быстрее, чем итерационная в 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 со следующими параметрами: gcc grad.c -O3 -lrt -o dg

Результат моего кода:

Minimum : 0.000487
Minimum : 0.000487
time_iter:127 ms, time_rec:19 ms, ratio (dif1/dif2) :6.68421
End.

Я прочитал поток, который также спрашивает, работает ли рекурсивная версия алгоритма быстрее, чем итерационная. Объяснение там заключалось в том, что рекурсивная версия с использованием стека и другая версия с использованием некоторых векторов, доступ к куче, замедляли итеративную версию. Но в этом случае (насколько я понимаю) я просто использую стек в обоих случаях.

Я что-то упускаю? Что-нибудь очевидное, чего я не вижу? Я неправильно измеряю время? Есть идеи?

РЕДАКТИРОВАТЬ: Тайна раскрыта в комментарии. Как сказал @TonyK, инициализация printf замедляла первое выполнение. Извини, что упустил эту очевидную вещь.

Кстати, код компилируется без предупреждений. Я не думаю, что "return descgrad (.. "необходимо, так как условие остановки уже произошло раньше.

7
задан Pedrom 22 December 2011 в 18:08
поделиться