begin process at 2010 09 09 14:57:50
  Trouver un code source :
 
dans
 
Accueil > 

Code

 > 

Tutoriaux

 > PERFORMANCE : I++ OU ++I ?

PERFORMANCE : I++ OU ++I ?


 Information sur la source

Note :
9 / 10 - par 2 personnes
9,00 / 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10
Catégorie :Tutoriaux Niveau :Expert Date de création :03/11/2002 Date de mise à jour :04/11/2002 22:10:01 Vu :4 797

Auteur : vieuxLion

Ecrire un message privé
Commentaire sur cette source (30)
Ajouter un commentaire et/ou une note

 Description

Cliquez pour voir la capture en taille normale
Bien sûr, il y a parfois des raisons pour choisir i++ plutôt que ++i
mais vous êtes vous posé la question de la performance ?
Surtout lorsque l'on utilise cette construction à répétition ...
dans une boucle par exemple. Alors :
votez vous pour i++ (comme la majorité des développeurs),
pour ++i (la minorité) ou pensez vous que c'est équivalent (ne sait pas) ?

Voyons cela de l'intérieur : à l'occasion de la surcharge des opérateurs ++
  

Source

  • /*
  • On vous donne la classe A suivante :
  • class A
  • {
  • private: int i_;
  • public:
  • A(int i) : i_(i){}
  • void print() const {cout << "valeur A=" << i_ << endl;}
  • };
  • On vous demande de supporter le "Use Case" suivant :
  • int main(){
  • A a(0);
  • a++.print();
  • (++a).print();
  • }
  • 0) Question préliminaire :
  • ---------------------------
  • Quelle est l'arité de ++ dans a++ ? et dans ++a ?
  • (l'arité d'un opérateur est son nombre de paramètres)
  • la réponse dans les deux cas devrait être UN
  • Donc, en l'implémentant comme méthode de la classe A, et en tenant compte
  • du paramètre caché 'this', elle ne doit avoir aucun paramètre
  • Comment différencier alors le cas a++ du cas ++a ?
  • Les standards répondent à ce problème en imposant un paramètre 'int'
  • à la version postfixée
  • I) Commençons par le premier opérateur :
  • -----------------------------------------
  • l'implémentation de la version postfixée de l'opérateur ++
  • Quel est le prototype ?
  • Ecrivons la version complète de l'opérateur (sa vision compilateur)
  • a++ est équivalent à a.operator++(int)
  • Que doit faire cet opérateur ?
  • d'abord incrémenter 'a', ensuite renvoyer l'ancienne valeur de 'a'
  • On remarquera qu'ici, il est "NECESSAIRE DE CREER UN OBJET TEMPORAIRE"
  • voici notre implémentation comme méthode de la classe A:
  • ?A? operator++(int)
  • { A clone(*this); //ceci est un appel au Ctor de copie de A
  • //permet de mémoriser l'ancienne valeur
  • ++i_; //incrémente l'objet courant
  • return clone; //renvoie l'ancienne valeur
  • } // ici appel au "DTOR DE L'OBJET TEMPORAIRE"
  • où ?A? représente soit 'A', 'const A', 'A&' ou 'const A&'
  • On élimine les pointeurs car le résultat de a++ est forcément un espèce de A
  • Comment choisir ?
  • Eliminons les références car l'objet renvoyé est temporaire (créé sur la pile)
  • il disparait dès la sortie du bloc '}', il est "NECESSAIRE DE RENVOYER UNE COPIE"
  • J'espère maintenant que vous êtes dégoutés du POST-FIXE !
  • Pour départager les ex-aequos (A et const A) voyons comment se comporte
  • l'opérateur des types de base (l'int par exemple)
  • Testons le code suivant :
  • int i(0); i++++;
  • Une erreur de compilation survient car l'opérateur ++ postfixé des 'int'
  • attend une L-VALUE (Left-value).
  • L-VALUE : variable possédant une zone de mémoire accessible en lecture/écriture
  • donc en particulier, pas une variable temporaire, ni une const.
  • En résumé, une variable pouvant être placée à gauche du signe =
  • Ceci nous donne notre réponse :
  • le type de retour DOIT être un 'const A' plutôt que 'A' pour être conforme au standards
  • On peut alors tester le premier opérateur ainsi
  • int main()
  • {
  • int i(0);
  • //i++++; ne compile pas ++ requiert l-value
  • A a(0);
  • //a++++; // ne compile pas si operator++(int) retourne un const
  • cout << "valeur i=" << i++ << endl;//renvoie 0
  • cout << "valeur i=" << i << endl;//renvoie 1
  • a++.print();//renvoie 0 : attention à bien prototyper la méthode print const
  • a.print();//renvoie 1
  • return 0;
  • }
  • II) Deuxième opérateur :
  • -----------------------------------------
  • Quel est le prototype de la version préfixée de l'opérateur ++ ?
  • ++a est équivalent à a.operator++()
  • Que doit faire cet opérateur ?
  • d'abord incrémenter 'a', ensuite renvoyer la nouvelle valeur de 'a'
  • On remarquera qu'ici, que l'on n'a pas besoin d'objet temporaire (COOL)
  • voici notre implémentation comme méthode de la classe A:
  • ?A? operator++()
  • { ++i_; //incrémente l'objet courant
  • return *this; //le renvoie
  • }
  • On peut renvoyer un 'A', 'const A', 'A&' ou 'const A&'
  • Le meilleur pour les performances est de renvoyer par référence
  • Voyons si elle doit être const ou non avec la même technique que précédemment
  • on teste
  • ++++i; ... et ça marche !
  • On peut donc retourner un A& (et c'est préférable pour imiter les types de base)
  • */
  • #include <iostream.h>
  • class A
  • {
  • private: int i_;
  • public: A(int i) : i_(i){}
  • void print() const {cout << "valeur A=" << i_ << endl;}
  • const A operator++(int)
  • { A clone(*this); //ceci est un appel au Ctor de copie de
  • //permet de mémoriser l'ancienne valeur
  • ++i_; //incrémente l'objet courant
  • return clone; //renvoie l'ancienne valeur
  • }
  • A& operator++()
  • { ++i_; //incrémente l'objet courant
  • return *this; //le renvoie
  • }
  • };
  • int main()
  • {
  • int i(0);
  • //i++++; ne compile pas ++ requiert l-value
  • A a(0);
  • //a++++; // ne compile pas si operator++(int) retourne un const
  • //test post fixé
  • cout << "valeur i=" << i++ << endl;//renvoie 0
  • cout << "valeur i=" << i << endl;//renvoie 1
  • a++.print();//=> 0 : attention à bien prototyper la méthode print const
  • a.print();//=> 1
  • //test pré fixé
  • cout << "valeur i=" << ++i << endl;//renvoie 2
  • cout << "valeur i=" << i << endl;//renvoie 2
  • (++a).print(); //=> 2 //parenthèses nécessaires (précédence de . sur ++)
  • a.print(); //=> 2
  • return 0;
  • }
  • /* "CONCLUSION":
  • Faisons le bilan :
  • en notation "POST-FIXE" :
  • un Ctor pour l'objet temporaire (Ctor de Copie ou Ctor défaut+Affectation)
  • l'incrémentation
  • un Ctor de Copie pour le retour par valeur
  • un Dtor de l'objet temporaire
  • en notation "PRE-FIXE" :
  • l'incrémentation
  • Un dernier mot pour dire que les types de bases se comportent de la même
  • manière que les classes (une temporaire), même si les dégâts sont moins flagrants
  • "il n'y a pas de différence dans le cas d'int" (merci aux commentaires ci-dessous . le 04/11)
  • Et si notre classe avait des données membres de type classe, et/ou des
  • classes de bases ... le poids des Ctor/Dtors devient ENORME...
  • */
/*
On vous donne la classe A suivante :
class A
{
private: int i_;
public:
  A(int i) : i_(i){}
  void print() const {cout << "valeur A=" << i_ << endl;}
};
On vous demande de supporter le "Use Case" suivant :

int main(){
  A a(0);
  a++.print();
  (++a).print();
}

0) Question préliminaire : 
---------------------------
Quelle est l'arité de ++ dans a++ ? et dans ++a ?
(l'arité d'un opérateur est son nombre de paramètres)
la réponse dans les deux cas devrait être UN
Donc, en l'implémentant comme méthode de la classe A, et en tenant compte
du paramètre caché 'this', elle ne doit avoir aucun paramètre
Comment différencier alors le cas a++ du cas ++a ?
Les standards répondent à ce problème en imposant un paramètre 'int' 
à la version postfixée

I) Commençons par le premier opérateur : 
-----------------------------------------
l'implémentation de la version postfixée de l'opérateur ++
Quel est le prototype ?
Ecrivons la version complète de l'opérateur (sa vision compilateur)
a++ est équivalent à a.operator++(int)
Que doit faire cet opérateur ?
 d'abord incrémenter 'a', ensuite renvoyer l'ancienne valeur de 'a'
On remarquera qu'ici, il est "NECESSAIRE DE CREER UN OBJET TEMPORAIRE"
voici notre implémentation comme méthode de la classe A:
?A? operator++(int)
{ A clone(*this); //ceci est un appel au Ctor de copie de A
               //permet de mémoriser l'ancienne valeur
  ++i_;     //incrémente l'objet courant
  return clone;   //renvoie l'ancienne valeur
  } // ici appel au "DTOR DE L'OBJET TEMPORAIRE"


où ?A? représente soit 'A', 'const A', 'A&' ou 'const A&'
On élimine les pointeurs car le résultat de a++ est forcément un espèce de A
Comment choisir ?
Eliminons les références car l'objet renvoyé est temporaire (créé sur la pile)
il disparait dès la sortie du bloc '}', il est "NECESSAIRE DE RENVOYER UNE COPIE"
J'espère maintenant que vous êtes dégoutés du POST-FIXE !

Pour départager les ex-aequos (A et const A) voyons comment se comporte 
l'opérateur des types de base (l'int par exemple)
Testons le code suivant :
 int i(0); i++++;
Une erreur de compilation survient car l'opérateur ++ postfixé des 'int'
attend une L-VALUE (Left-value). 
 L-VALUE : variable possédant une zone de mémoire accessible en lecture/écriture
      donc en particulier, pas une variable temporaire, ni une const.
      En résumé, une variable pouvant être placée à gauche du signe =
Ceci nous donne notre réponse : 
le type de retour DOIT être un 'const A' plutôt que 'A' pour être conforme au standards

On peut alors tester le premier opérateur ainsi
int main()
{
	int i(0);
	//i++++; ne compile pas ++ requiert l-value
	A a(0);
	//a++++; // ne compile pas si operator++(int) retourne un const
	cout << "valeur i=" << i++ << endl;//renvoie 0
	cout << "valeur i=" << i << endl;//renvoie 1
	a++.print();//renvoie 0 : attention à bien prototyper la méthode print const
	a.print();//renvoie 1

	return 0;
}

II) Deuxième opérateur : 
-----------------------------------------
Quel est le prototype de la version préfixée de l'opérateur ++ ?
++a est équivalent à a.operator++()
Que doit faire cet opérateur ?
 d'abord incrémenter 'a', ensuite renvoyer la nouvelle valeur de 'a'
On remarquera qu'ici, que l'on n'a pas besoin d'objet temporaire (COOL)

voici notre implémentation comme méthode de la classe A:
?A? operator++()
{ ++i_;            //incrémente l'objet courant
  return *this;   //le renvoie
  }
On peut renvoyer un 'A', 'const A', 'A&' ou 'const A&'
Le meilleur pour les performances est de renvoyer par référence
Voyons si elle doit être const ou non avec la même technique que précédemment
on teste 
++++i; ... et ça marche !
On peut donc retourner un A& (et c'est préférable pour imiter les types de base)
 
*/

#include <iostream.h>
class A
{
private: int i_;
public: A(int i) : i_(i){}
  void print() const {cout << "valeur A=" << i_ << endl;}
  const A operator++(int)
{ A clone(*this); //ceci est un appel au Ctor de copie de 
                  //permet de mémoriser l'ancienne valeur
  ++i_;           //incrémente l'objet courant
  return clone;   //renvoie l'ancienne valeur
  }
  A& operator++()
{ ++i_;           //incrémente l'objet courant
  return *this;   //le renvoie
  }
};

int main()
{
	int i(0);
	//i++++; ne compile pas ++ requiert l-value
	A a(0);
	//a++++; // ne compile pas si operator++(int) retourne un const
	
	//test post fixé
	cout << "valeur i=" << i++ << endl;//renvoie 0
	cout << "valeur i=" << i << endl;//renvoie 1
	a++.print();//=> 0 : attention à bien prototyper la méthode print const
	a.print();//=> 1

	//test pré fixé
	cout << "valeur i=" << ++i << endl;//renvoie 2
	cout << "valeur i=" << i << endl;//renvoie 2
	(++a).print(); //=> 2 //parenthèses nécessaires (précédence de . sur ++)
	a.print(); //=> 2
	return 0;
}

/* "CONCLUSION":
Faisons le bilan :
en notation "POST-FIXE" :
un Ctor pour l'objet temporaire (Ctor de Copie ou Ctor défaut+Affectation)
l'incrémentation
un Ctor de Copie pour le retour par valeur
un Dtor de l'objet temporaire

en notation "PRE-FIXE" :
l'incrémentation

Un dernier mot pour dire que les types de bases se comportent de la même 
manière que les classes (une temporaire), même si les dégâts sont moins flagrants
"il n'y a pas de différence dans le cas d'int" (merci aux commentaires ci-dessous . le 04/11)
Et si notre classe avait des données membres de type classe, et/ou des
classes de bases ... le poids des Ctor/Dtors devient ENORME...
*/
   



 Sources du même auteur

Source avec Zip Source avec une capture UN BUFFEROVERRUN : LE DÉBORDEMENT DE PILE
CONNAISSEZ VOUS PRINTF ?
Source avec Zip Source avec une capture Source .NET (Dotnet) C++ MANAGÉ PAR LES HELLO WORLDS (DOTNET)
Source avec Zip SIMPLE MOYEN DE FAIRE UNE DLL À PARTIR DE FONCTIONS CPP
LE VECTEUR EST UN SACRÉ COPIEUR

 Sources de la même categorie

Source avec Zip Source avec une capture QCSSCOMPRESSOR par alphaone
AFFICHAGE D'UN TRIANGLE ISOCELE par nabche
Source avec Zip GESTION D'UNE BIBLOTHEQUE par leclerro19
[PSP]HELLO WORLD par Mario1095
Source avec Zip Source avec une capture UTILISER LA LIB DIRENT par Lemng

Commentaires et avis

Commentaire de ndj55 le 03/11/2002 21:03:42

Pas mal... Mais tu es sur de ce que tu dis?
Un ++i serait plus rapide qu'un i++ ?

Commentaire de Jhep le 03/11/2002 22:13:29

euh... tu peux répéter stp ?

Commentaire de Jhep le 03/11/2002 22:40:06

Démonstration un peu plus explicite :

#include &lt;stdio.h&gt;
#include &lt;time.h&gt;

void main()
{
time_t timer;
int s = 0, i = 0;
printf("Attendez 10 seconds SVP.
");
time(&timer);
s = timer;
while(timer - s &lt; 10){
time(&timer);
i++;
}
printf("Resultat de la boucle avec i++ : %i
", i);

printf("Attendez 10 seconds SVP.
");
i = 0;
time(&timer);
s = timer;
while(timer - s &lt; 10){
time(&timer);
++i;
}
printf("Resultat de la boucle avec ++i : %i
", i);
getchar();
}

Commentaire de vieuxLion le 03/11/2002 23:26:45

merci du test Jhep
tu vois que l'on fait plus de boucles avec du ++i que du i++ ! (5%)

j'en profite pour joindre mon Benchmark dans la capture d'écran
elle indique 3% de gain pour une classe contenant un int, plus de 80% pour une classe contenant dix doubles et un int et 300% pour une classe contenant un char[256] et un int, etc...

Commentaire de Galett le 04/11/2002 00:16:12

juste un commentaire pour vieux lion, ça n'a rien à voir avec ton explication, c juste pour te féliciter des morceaux de code que tu laisses sur ce site, ca fait qqs semaines que tu en postes, ils sont très éducatifs, alors voila juste un clap clap !
sinon tu n'envisages pas de mettre toutes tes connaissances sur un site internet ?
ce serai très bénéfique pour de nombreux programmeurs je pense. :o)

Commentaire de ndj55 le 04/11/2002 20:18:46

Je suis plus ou moins d'accord avec ta démonstration vieuxLion...
Regarde cela:
---------------------------------------------
for (i=0; i&lt;32; ++i) // PreFix
printf("%i", i);

for (i=0; i&lt;32; i++) // PreFix
printf("%i", i);
---------------------------------------------

regarde le code asm produit pas Visual Studio 6 avec optimisation:
---------------------------------------------
$L43572:
; Line 20
push esi
push OFFSET FLAT:??_C@_02JAFN@?$CFi?$AA@ ; `string'
call _printf
add esp, 8
inc esi
cmp esi, 32 ; 00000020H
jl SHORT $L43572
; Line 22
xor esi, esi
; Line 26
npad 7
$L43576:
; Line 23
push esi
push OFFSET FLAT:??_C@_02JAFN@?$CFi?$AA@ ; `string'
call _printf
add esp, 8
inc esi
cmp esi, 32 ; 00000020H
jl SHORT $L43576
---------------------------------------------

Et oui c'est exactement la meme chose pour les deux boucles... Donc pas de gain de perfs ici...

Commentaire de GoldenEye le 04/11/2002 20:40:17

ndj55=&gt; hors sujet je crois, il est question de surcharge de l'opérateur ++ d'après ce que j'ai compris. Ici ++i ou i++ est interprété de la même manière vu que i est un pauvre int. Par contre si c'est une structure plus évoluée, ça commence à changer des choses.
Je me contenterai de critiquer le titre un peu racoleur (faut bien que je justifie mon label de râleur invétéré !). pour le reste nickel

Commentaire de GoldenEye le 04/11/2002 20:42:19

Nan nan pas aussi hors sujet, j'ai rien dit. J'ai retesté ton truc ndj55 et je suis d'accord avec toi. Qui m'explique ? Vieuxlion, tu as fait ça avec quel compilateur ?

Commentaire de vieuxLion le 04/11/2002 22:03:49

Merci tout le monde : le titre racolleur a marché... nombreux commentaires intéressants...
L'article (et mon bench) porte sur les structures et classes
En ce qui concerne les 'int' la variable temporaire est utilisée dans les deux cas car l'assembleur travaille déjà avec un Accumulateur et la zone mémoire.
C'est bien vu : il n'y a pas de différence... et le test de Jhep a plusieurs défauts :
1) il passe plus de temps à calculer time() que i++
2) le résultat n'est pas reproductible : inverser les deux tests pour voir !!!
3) il ne booste pas le process en real time pour être plus fiable : par ex :
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
pour Windows
mon Bench utilise GetTickCount() avant et après la boucle

Commentaire de Xs le 04/11/2002 23:15:58

piouuuuuu !!!! alors, au final : c'est comme c'est demo de maths qui nous disent que 1 = 0 !
En clair, une erreur est quelque part, mais personne, ou du moin je crois, na la solutions.... donc pout moi ++i = i++ tjr. j'etais convaincu par le teste de jhep mais l'asm plus puissant et vrai lui donne tord.... ??!!

Commentaire de Setaou le 05/11/2002 09:34:13

il me semblait que pour un printf("%i", i++); i était affiché puis incrémenté, alors que pour printf("%i", ++i); il était incrémenté puis affiché ... Comment ca peut produire le même code ASM ?

Commentaire de Galett le 05/11/2002 14:05:27

il me semble, si qq1 peut confirmer, que pour le test de ndj55, il est normal que le code asm produit soit le même, car visual commence par des macros compilations (c'est surement pas le terme exact, mais ca devrait se rapprocher :)
Je m'explique, pour les 2 boucles qui sont différentes au niveau syntaxique, visual va faire une première passe pour essayer d'optimiser tout ça. Et ainsi il va transformé la seconde boucle en première boucle pour optimiser justement.
C'est comme si vous aviez sur une seule ligne :
i++;
j'espère bien que le compilateur va le traduire en ++i, sinon il serait pas très bon optimisateur, non ?


enfin c'est surtt une supposition, si qq1 pouvait le confirmer :)

Commentaire de Kinamstrong le 05/11/2002 17:57:31

la discussion est de haut niveau et vous m'epatez !!!!!!
Mon prof me parlait d'une différence benine en tre les deux (++i et i++) mai la alors en faire un sujet c de la balle et franchement intéressant.
Au fait Galett , ta "macro compilation" ce n'est pas la précompilation!!!!!
@+

Commentaire de Kinamstrong le 05/11/2002 17:59:30

i++ ou ++i ne serait pas comme des "alias" sous TUX ??????
des sortes de raccourcis de commandes.
Obtient-on les mêmes resultats avec i=i+1;

??????

Commentaire de ndj55 le 06/11/2002 13:04:17

Kinamstrong -&gt; Je pense que l'on obtiendrait les memes résultats oui... En effet,quand le compilateur optimise,il prend en compte des cas particuliers... Additioner ou soustraire 1 est un cas particulier dans la mesure où il existe deux instructions destinées à ce genre d'opérations (inc et dec). C'est le meme principe que pour les multiplications/divisions par des entiers puissances de 2 (2,4,8,16...). En effet,si ton compilateur optimise correctement,il doit transformer i*=2 en i&lt;&lt;1 soit en ASM: shl ADRESS i,1 .
La différence majeure entre i++ et ++i réside en fait dans le fait que dans certains cas (fonction en général), la position de ++ (ou --) indique le moment où l'incrémentation doit être faite.... Ainsi,en notation préfixe cela signifie que l'on incrémente avant; en notation post-fixe,on incrémente après...

Commentaire de ndj55 le 06/11/2002 13:14:57

vieuxLion -&gt; Une petite remarque... GetTickCount() est moi rapide que timeGetTime(). Si je peux me permettre,voilà un bon code de timer:

------------------------------------------------

#define NBR_TESTS 512 // Le Nombre De Mesures A Effectuer
ofstream StatFile;
int i;
unsigned long StartTime;
unsigned long EndTime;
unsigned int ElapsedTime[NBR_THREADS];
unsigned long TotalTime = 0;
float AverageTime;

for (i = 0; i &lt; NBR_TESTS; ++i)
{
StartTime = timeGetTime();
/* C'est ici que doit se situer un appel unique à la fonction testée */
EndTime = timeGetTime();
ElapsedTime[i] = EndTime - StartTime;
}

StatFile.open("Stat.txt");

for (i = 0; i &lt; NBR_TESTS; ++i)
{
StatFile &lt;&lt; "Time For Thread " &lt;&lt; i &lt;&lt; " : " &lt;&lt; ElapsedTime[i] &lt;&lt; endl;
TotalTime += ElapsedTime[i];
}

StatFile &lt;&lt; "---------------------------
Total Time: " &lt;&lt; TotalTime &lt;&lt; endl;
AverageTime = (float) TotalTime / (float) NBR_TESTS;
StatFile &lt;&lt; "Average Time: " &lt;&lt; AverageTime &lt;&lt; endl;
StatFile.close();

-----------------------------------

Ici,un appel à la fonction entre les deux mesures de temps...
Dans un prog qui dessine des fractales,les écarts entre les fonctions identiques avec les meme arguments sont de l'ordre de 1 ou 2 millisecondes... Ce qui prouve que le timer est presque parfait,les différences de mesure pouvant etre dû aux aléas du systeme ou au manque de précision dans la mesure du temps...
Si quelqu'un veut bien refaire les tests de ce que dit vieuxLion avec cette méthode...
Sinon, si vous pensez que ce timer est encore imparfait... utilisez le Zen Timer de Michael Abrash écrit en ASM... Mais je pense qu'ici cé inutile...

Commentaire de ndj55 le 06/11/2002 13:16:01

euh dans le code ci dessus:
unsigned int ElapsedTime[NBR_THREADS]; es à remplacer par
unsigned int ElapsedTime[NBR_TESTS];

Commentaire de trinitacs le 06/11/2002 14:53:49

Je confirme que ++i est plus raide que i++. Je n'ai pas tout lu car je n'ai pas le temps :( donc je risque de répéter ce que certains ont dit (enfin j'espère pas). Car quand on tape i++ une copie de i sera créé pour faire croire que i sera incrémenter après alors que ++i incrémente directement i. C'est comme si on sucharge l'opérateur ++ pour une classe. Si il est après la variable on renverra une copie de i à partir de la fonction operator++ ( int ); ( le int signale que c'est posincrémentation et rien pour une préincrémentation ).
Bon bref je vienx soutenir vieux lion car Jhep n'est pas complètement convaincu.
Sinon je répon à la question de vieux utlisez vous i++ ou ++i. J'utilise c++ car c'est plus jolie, sinon si la boucle est grande et la performance primordiale j'écris ++c .ourquoi c et non pas i comme tout le monde?? Par ce que c c'est le nom du langage et puis c c'est la premièere lettre de compteur :)

Sinon j'ai pas compris ton tableau?? i++ et ++i pour le int c'est kif kif mais pour les double ++i c'est 5 kilomèetre devant?

En tout cas merci vieux lion d'avoir mis une source avec les tests car je ne savais pas que la différence de temps était aussi grande pour les double.

Si après l'exemple de vieux lion il y a encore des gens qui pense que i++ et ++i sont aussi rapide je me tire une balle :(

Commentaire de Galett le 06/11/2002 23:55:53

précompilation, voila le terme m'était sorti de la tête :)
merci Kinamstrong !

Commentaire de ndj55 le 07/11/2002 21:45:18

trinitacs -&gt; tu aurais du tout lire... regarde mon truc de code ASM... Le code ASM est le meme dans les  deux boucles donc pas d'accélération ici...
Perso,j'utilise les deux,c'est selon mes humeurs...

Commentaire de trinitacs le 08/11/2002 17:09:16

bdj55 &gt;&gt; Je ne suis pas d'accord pour dire que le code asm est le même pour ++i et i++. C'est vrai que d'après ce que tu nous montre on pourrait dire que c'est la même chose. Mais tu le sais bien comme tout le monde que i++ et ++i c'est différent donc le code source en asm ne peut pas être le même pour les deux.
Ou peut tu voir la sortie asm de ton compilo stplè?

Commentaire de ndj55 le 08/11/2002 18:37:17

trinitacs-&gt; Sous Visual Studio tu ajoutes l'option /FA pour le compilateur... Je ne sais pas pour GCC... Je t'assure que le code est le meme...

$L43572:
push esi
push OFFSET FLAT:??_C@_02JAFN@?$CFi?$AA@ ; `string'
call _printf
add esp, 8
inc esi
cmp esi, 32 ; 00000020H
jl SHORT $L43572

$L43576:
push esi
push OFFSET FLAT:??_C@_02JAFN@?$CFi?$AA@ ; `string'
call _printf
add esp, 8
inc esi
cmp esi, 32 ; 00000020H
jl SHORT $L43576

Voilà deux boucles qui font la meme chose mais l'incrmentation est différente... Tu vois bien que c'est la meme chose: "inc esi"...

Commentaire de Galett le 09/11/2002 01:37:45

/FA ? ca fait quoi exactement ?
*va tester ça*

Commentaire de ndj55 le 09/11/2002 14:50:44

l'option /FA permet de générer un code asm intermédiaire...
il y a aussi /FC,qui génere un code COD...

Commentaire de Lightness1024! le 10/11/2002 12:15:47

arf vous apportez de l'importance a cette difference ? sur des processeurs a 2 GHz perdre 3 cycles c pas un drame (OK si ya ke ca dans la boucle) mais en général un programme ca fait des milliers de lignes et mieux vaut se pencher sur les fonctions vraiment lentes style sqrt ou cos, sin, atn etc...

Commentaire de bleyblue le 19/11/2002 18:11:39

Différence entre i++ et ++i :
Pour les opérations sur les types de données simples (int par exemple), la différence ne se situe pas dans l'opération elle - même (les codes asm sont équivalents) mais sur l'évaluation de l'expression. Je m'explique :
int i = 5;
( ++i == 5 ) est faux car l'incrémentation a lieu avant l'évaluation
int i = 5;
( i ++ == 5 ) est vrai car l'incrémentation a lieu après l'évaluation
J'espère que c'est clair...

Commentaire de PiXator le 21/11/2002 15:22:20

Et Ben !!!!!!!!!!!!!!!!!!!!!!!!

Commentaire de JackosKing le 31/12/2002 15:20:56

heu... en asm 68k:
int *a=x;
b=*(++a); est beaucoup plus lente que b=*(a++);
equivalent a: (a= a0 b=d0 );
addq #1,a0
move.l (a0),d0
contre:
move.l (a0)+,d0
...
@+

Commentaire de Croqmort le 12/01/2003 03:03:59

il ne faut pas oublier que le compilateur optimise le code, et transforme les i++ en ++i si ça s'avere utile.

le i++ requiert de creer une variable temporaire, car on peut faire tableau[i++]; et i va exister dans 2 etat un etat non incrementé temporaire pour l'indice du tableau, et un etat incrementer pour la nouvelle valeur de i.

il faudrai transformer en asm une class integer refaite avec post incrementation et pre incrementation et la transformer en asm, en desactivant si possible les optimisations.

Commentaire de pasm le 23/10/2005 22:47:10

Un détail trés important que vous avez tous oublié: le ++i incrémente i avant même de l'utiliser, alors que i++ fait de la post-incrémentation, en performance pure c'est identique. Il n'y a que la manière de la utiliser en fonction de l'optimisation des boucles que ça change...

 Ajouter un commentaire




Nos sponsors


Sondage...

CalendriCode

Septembre 2010
LMMJVSD
  12345
6789101112
13141516171819
20212223242526
27282930   

Consulter la suite du CalendriCode

 
Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils.
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés

Google Coop CodeS-SourceS Google Coop CodeS-SourceS
Temps d'éxécution de la page : 0,842 sec (4)

Nous contacter | Annoncer sur CodeS-SourceS | Mentions légales