méta-programmation et chronomètre
Bonjour,
je développe des coeurs de calculs (résolution d'équations) et je suis donc très intéressé par la minimisation des temps de calculs. J'ai lu l'article de Laurent Gomila sur la méta-programmation (http://loulou.developpez.com/tutoriels/cpp/metaprog/). Cet article est très clair mais j'ai cependant quelques questions :
1) tout doit connu par le compilateur. Certes. Mais dans mon cas toutes mes inputs sont lues à partir de fichiers texte (les fichiers d'initialisation). Donc le prétraitement consiste à lire ces fichiers, le traitement à effectuer les calculs et le post traitements à la visualisation graphique des résultats. Mais donc, à la compilation, rien n'est connu par le compilateur car tout est lu à partir de fichiers texte. Comment appliquer la méta-programmation ? Car les exemples donnés par Laurent Gomila dans son article sont donnés pour comprendre ce qu'est la méta-programmation. Il est rare de calculer factorielle(4). En général on fait plutôt factorielle(n) où n est lu à partir d'un fichier texte (donc inconnu à la compilation)
2) dans son article, Laurent Gomila utilise des struct et des enum. Sur le site suivant http://fr.wikipedia.org/wiki/C_plus_plus il y a un exemple de méta-programmation :
Code:
1 2 3 4 5 6 7 8 9 10 11 12
|
template< size_t N >
struct CalcCompileTime
{
static size_t Fact = N * CalcCompileTime< N - 1 > ;
};
template<0>
struct CalcCompileTime<0>
{
static size_t Fact = 1 ;
}; |
que vaut-il mieux utiliser : les enums ou les static ?
3) j'ai codé un exemple donné par Laurent Gomila (le cosinus). C'est plus lent que le "simple" cosinus de <cmath> (d'un facteur 10). Où se trouve mon erreur ? Les fichiers sont en pièce jointe
4) La méta-programmation étant plus rapide que la programmation "normale", j'en déduis donc qu'il vaut mieux utiliser des librairies de calculs comme Boost plutôt que lapack non ?
Merci pour vos réponses, et je vais continuer à étudier de près cette technique de programmation car elle m'a l'air très intéressante !
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
| #include <cmath>
#include <iostream>
using namespace std;
double GetClock ( void );
#define ITERMAX 1000000
template <int I> inline double Factorielle()
{
return I * Factorielle<I - 1>();
}
template <> inline double Factorielle<0>()
{
return 1.0;
}
template <int N> inline double Puissance(double x)
{
return x * Puissance<N - 1>(x);
}
template <> inline double Puissance<0>(double x)
{
return 1.0;
}
// Ici aussi, N resprsente l'ordre de dveloppement
template <int N> inline double Cosinus(double x)
{
return Cosinus<N - 1>(x) + (N % 2 ? -1 : 1) * Puissance<2 * N>(x) / Factorielle<2 * N>();
}
template <> inline double Cosinus<0>(double x)
{
return 1.0;
}
int main(void)
{
double x = 3.14159265358979;
double sum = 0.;
double start, end;
double d;
cout<<"version non metaprogrammation"<<endl;
for(int i = 0 ; i < ITERMAX ; i++)
{
start = GetClock();
d = cos(x);
end = GetClock();
sum += end - start;
}
cout<<"d = "<< d <<endl;
cout<<"chrono = " << sum / ITERMAX << endl;
cout<<"version metaprogrammation"<<endl;
sum = 0.;
for(int i = 0 ; i < ITERMAX ; i++)
{
start = GetClock();
d = Cosinus<7>(x);
end = GetClock();
sum += end - start;
}
cout<<"d = "<< d <<endl;
cout<<"chrono = " << sum / ITERMAX << endl;
return 0;
} |
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
| /******************************************************************************
* *
* Import Header Files *
* *
******************************************************************************/
#include<stdlib.h>
#include<stdio.h>
#include <time.h>
#include <sys/time.h>
#if defined LINUX || defined MAC
#define UNIX
#include <unistd.h>
#endif
#include<string.h>
#include <errno.h>
/******************************************************************************
* *
* Private Macros *
* *
******************************************************************************/
#define CLOCKERROR \
do \
{ \
fprintf( stderr, "%s:%d : GetClock() failed (%s)\n",__FILE__,__LINE__,strerror( errno ));\
exit(EXIT_FAILURE); \
} \
while(0)
/******************************************************************************
* *
* Public Functions Implementation *
* *
******************************************************************************/
double GetClock ( void )
{
/*
This function returns the time (like clock()), but it returns the absolute
real time (whereas clock() returns the time compared to the program). It
returns the time in seconde with a precision until the micro-seconde.
It returns -1 if there was an error
source : http://www.developpez.net/forums/showthread.php?t=324756
*/
double d=-1. ;
#ifndef UNIX
#ifdef WINDOWS
struct timeval tval ;
struct timezone *tz=NULL ;
timerclear(&tval);
if ( gettimeofday(&tval, tz) ) CLOCKERROR;
d = ((double)(tval.tv_usec)/1000000.0) ;
d = (double) tval.tv_sec + d ;
#else /* neither WINDOWS nor UNIX are defined */
struct timespec cur_time ;
if (clock_gettime(CLOCK_REALTIME, &cur_time)) CLOCKERROR;
d = ((double)(cur_time.tv_nsec)/1000.0) / 1000000.0 ;
d = (double) cur_time.tv_sec + d ;
#endif /* end #ifdef WINDOWS */
#else /* UNIX is defined */
struct timeval tval ;
struct timezone *tz=NULL ;
timerclear(&tval);
if ( gettimeofday(&tval, tz) ) CLOCKERROR;
d = ((double)(tval.tv_usec)/1000000.0) ;
d = (double) tval.tv_sec + d ;
#endif /* end #ifndef UNIX */
return d ;
} |