Sto verificando la differenza tra due implementazioni della discesa del gradiente, suppongo che dopo l'ottimizzazione del compilatore entrambe le versioni dell'algoritmo sarebbero equivalenti.Perché una versione ricorsiva di una funzione sarebbe più veloce di una iterativa in C?
Per la mia sorpresa, la versione ricorsiva era significativamente più veloce. Non ho scartato un difetto reale su nessuna delle versioni o persino nel modo in cui sto misurando il tempo. Ragazzi, potete darmi qualche informazione per favore?
Questo è il mio codice:
#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");
}
sto compilazione con gcc 4.5.2 su Ubuntu 11.04 con le seguenti opzioni: gcc grad.c -O3 -lrt -o dg
L'uscita del mio codice è:
Minimum : 0.000487
Minimum : 0.000487
time_iter:127 ms, time_rec:19 ms, ratio (dif1/dif2) :6.68421
End.
ho letto un thread che chiedono anche di una versione ricorsiva di un algoritmo di essere più veloce di quello iterativo. La spiegazione laggiù era che essendo la versione ricorsiva che utilizzava lo stack e l'altra versione che utilizzava alcuni vettori, l'accesso all'heap stava rallentando la versione iterativa. Ma in questo caso (nel migliore dei casi) sto usando lo stack in entrambi i casi.
Mi manca qualcosa? Qualcosa di ovvio che non vedo? Il mio modo di misurare il tempo è sbagliato? Qualche intuizione?
MODIFICA: Mistero risolto in un commento. Come ha affermato @TonyK, l'inizializzazione di printf stava rallentando la prima esecuzione. Mi dispiace di aver perso quella cosa ovvia.
BTW, il codice viene compilato correttamente senza avvisi. Non credo che il "descgrad ritorno (.." è necessaria in quanto la condizione di arresto sta accadendo prima
Tutto "perché è più veloce?" le domande devono essere accompagnate dal codice assembly che elenca l'output del compilatore. –
Dov'è la dichiarazione di ritorno per 'descgrad' per il caso in cui l'istruzione' if' è falsa? Questo codice non dovrebbe essere compilato. –
@ user112358132134: nah, dovrebbe solo compilare con un avviso, no? –