Boucles For (académiques ...)

Le
Jean-marc
Hello,

je rebondis sur l'article de Driss.

Savez vous que en toute rigueur, on ne devrait utiliser
les variables de boucles QUE pour compter. En d'autres mots,
la variable de boucle ne devrait pas apparaître dans le corps de la boucle.
Cette règle est une règle de base d'algorithmique et en pratique, c'est
effectivement plus sur et plus correct d'un point de vue sémantique.

Ainsi, pour unitialiser un tableau, il ne faudrait pas écrire ceci :

Const TAILLE_TABLEAU As Long = 100000
Dim t(TAILLE_TABLEAU) As Long
Dim i As Long
Dim n As Long

For i = 1 To TAILLE_TABLEAU
t(i) = 10
Next i

Mais cela:

n = 0
For i = 1 To TAILLE_TABLEAU
n = n + 1
t(n) = 10
Next i

On pourrait objecter que la seconde forme va être plus lente :
on doit incrémenter une variable de plus.

Il n'en est rien : En plus d'être plus correcte, la seconde forme
peut même être très légèrement plus rapide !

Mais comment est-ce possible ?

En n'utilisant pas 'i' dans la boucle, on permet au compilateur
d'implémenter la boucle de façon optimale, en utilisant
des instructions rapides qui savent (par exemple) décrémenter et brancher
si zéro en un seul cycle, ou tout autre genre d'optimisation.
D'où le gain de temps. Et bien sur c'est valable dans tous les langages.

Conclusion : ne jamais essayer de se substituer au compilateur : celui-ci
est dans tous les cas bien plus malin que le programmeur. A vouloir faire
des "ruses" pour tenter des "optimisations", on empêche bien souvent ce
brave compilateur de faire correctment son job :-)

Bon week-end !

--
Jean-marc Noury (jean_marc_n2)
Microsoft MVP - Visual Basic
FAQ VB: http://faq.vb.free.fr/
mailto: remove '_no_spam_' ; _no_spam_jean_marc_n2@yahoo.fr
Vidéos High-Tech et Jeu Vidéo
Téléchargements
Vos réponses Page 1 / 2
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
aski
Le #16674081
Hello Jean-Marc,

"Jean-marc" discussion : 48b952ca$0$2847$
Hello,

je rebondis sur l'article de Driss.

Savez vous que en toute rigueur, on ne devrait utiliser
les variables de boucles QUE pour compter. En d'autres mots,
la variable de boucle ne devrait pas apparaître dans le corps de la
boucle.
Cette règle est une règle de base d'algorithmique et en pratique, c'est
effectivement plus sur et plus correct d'un point de vue sémantique.

Ainsi, pour unitialiser un tableau, il ne faudrait pas écrire ceci :

Const TAILLE_TABLEAU As Long = 100000
Dim t(TAILLE_TABLEAU) As Long
Dim i As Long
Dim n As Long

For i = 1 To TAILLE_TABLEAU
t(i) = 10
Next i

Mais cela:

n = 0
For i = 1 To TAILLE_TABLEAU
n = n + 1
t(n) = 10
Next i

On pourrait objecter que la seconde forme va être plus lente :
on doit incrémenter une variable de plus.

Il n'en est rien : En plus d'être plus correcte, la seconde forme
peut même être très légèrement plus rapide !

Mais comment est-ce possible ?

En n'utilisant pas 'i' dans la boucle, on permet au compilateur
d'implémenter la boucle de façon optimale, en utilisant
des instructions rapides qui savent (par exemple) décrémenter et brancher
si zéro en un seul cycle, ou tout autre genre d'optimisation.
D'où le gain de temps. Et bien sur c'est valable dans tous les langages.

Conclusion : ne jamais essayer de se substituer au compilateur : celui-ci
est dans tous les cas bien plus malin que le programmeur. A vouloir faire
des "ruses" pour tenter des "optimisations", on empêche bien souvent ce
brave compilateur de faire correctment son job :-)



Merci, c'est très instructif et nous allons sagement appliquer.
Qu'en est-il alors d'une boucle ayant le même objet mais implémentée avec do
while ou équivalent ?
La vitesse est-elle la même ?
--
Cordialement

Aski
MVP Windows Desktop Experience
Jean-marc
Le #16674711
aski wrote:
Hello Jean-Marc,




Merci, c'est très instructif et nous allons sagement appliquer.
Qu'en est-il alors d'une boucle ayant le même objet mais implémentée
avec do while ou équivalent ?



En toute rigueur, il faudrait appliquer le même principe, en faisant
par exemple :

n = 0
i = TAILLE_TABLEAU
While i > 0
n = n + 1
t(n) = 10
i = i - 1
Wend

Mais je pense que dans ce cas, on peut écrire directement :

i = TAILLE_TABLEAU
While i > 0
t(i) = 10
i = i - 1
Wend

La vitesse est-elle la même ?



Oui, car pour le compilateur, il n'y a de toute façon pas de For/Next
ni de While/Wend ni de Do/Loop.

Si tu écris une boucle d'initialisation, que tu utilises For, While ou
Do, dans tous les cas le code produit sera un truc comme ça (ou de
similaire) :

COMPTEUR = VALEUR_INITIALE
I = 1
LABEL1:
T[I] = V
INCREMENTE I
;L1 DECREMENTE COMPTEUR
;L2 COMPARE COMPTEUR, 0
;L3 SI PAS ZERO, GOTO LABEL1:
SUITE:
...

L'astuce, c'est que selon les compilos, les processeurs et l'allure
de la boucle, le compilateur peut faire des optimisations de bas
niveau intéressantes. Par exemple, utiliser pour les pas
(L1, L2 et L3) une seule instruction, consommant donc un seul cycle.

Note : bien sur, l'optimisation (la vitesse) n'est pas le but ici.
On n'optimise pas un programme de cette façon mais en choisissant
de meilleurs algortihmes, en rationalisant les choses, en préprocessant,
etc.

--
Jean-marc Noury (jean_marc_n2)
Microsoft MVP - Visual Basic
FAQ VB: http://faq.vb.free.fr/
mailto: remove '_no_spam_' ;
aski
Le #16677401
Bonjour Jean-Marc

"Jean-marc" discussion : 48b990aa$0$2862$

La vitesse est-elle la même ?



Oui, car pour le compilateur, il n'y a de toute façon pas de For/Next
ni de While/Wend ni de Do/Loop.

...

L'astuce, c'est que selon les compilos, les processeurs et l'allure
de la boucle, le compilateur peut faire des optimisations de bas
niveau intéressantes. Par exemple, utiliser pour les pas
(L1, L2 et L3) une seule instruction, consommant donc un seul cycle.

Note : bien sur, l'optimisation (la vitesse) n'est pas le but ici.
On n'optimise pas un programme de cette façon mais en choisissant
de meilleurs algortihmes, en rationalisant les choses, en préprocessant,
etc.



Merci Jean-Marc. :o)
--
Cordialement

Aski
MVP Windows Desktop Experience
Driss HANIB
Le #16685431
Salut Jean Marc
merci pour cette précision ..
je vais aussi m'y mettre comme Aski..

Driss

"Jean-marc" 48b952ca$0$2847$
Hello,

je rebondis sur l'article de Driss.

Savez vous que en toute rigueur, on ne devrait utiliser
les variables de boucles QUE pour compter. En d'autres mots,
la variable de boucle ne devrait pas apparaître dans le corps de la
boucle.
Cette règle est une règle de base d'algorithmique et en pratique, c'est
effectivement plus sur et plus correct d'un point de vue sémantique.

Ainsi, pour unitialiser un tableau, il ne faudrait pas écrire ceci :

Const TAILLE_TABLEAU As Long = 100000
Dim t(TAILLE_TABLEAU) As Long
Dim i As Long
Dim n As Long

For i = 1 To TAILLE_TABLEAU
t(i) = 10
Next i

Mais cela:

n = 0
For i = 1 To TAILLE_TABLEAU
n = n + 1
t(n) = 10
Next i

On pourrait objecter que la seconde forme va être plus lente :
on doit incrémenter une variable de plus.

Il n'en est rien : En plus d'être plus correcte, la seconde forme
peut même être très légèrement plus rapide !

Mais comment est-ce possible ?

En n'utilisant pas 'i' dans la boucle, on permet au compilateur
d'implémenter la boucle de façon optimale, en utilisant
des instructions rapides qui savent (par exemple) décrémenter et brancher
si zéro en un seul cycle, ou tout autre genre d'optimisation.
D'où le gain de temps. Et bien sur c'est valable dans tous les langages.

Conclusion : ne jamais essayer de se substituer au compilateur : celui-ci
est dans tous les cas bien plus malin que le programmeur. A vouloir faire
des "ruses" pour tenter des "optimisations", on empêche bien souvent ce
brave compilateur de faire correctment son job :-)

Bon week-end !

--
Jean-marc Noury (jean_marc_n2)
Microsoft MVP - Visual Basic
FAQ VB: http://faq.vb.free.fr/
mailto: remove '_no_spam_' ;







Sebastien
Le #16707211
Hum sur un plan académique, je dirais plutot de bannir la boucle for!
Enfin, ce que tu dis n'est pas totalement faux mais loin d'etre totalement
vrai!
Un compilo plus intelligent qu'un codeur ? je doute un peu quand meme!

Fais un code en C, sort le listing asm et dis moi qu'il n'est pas possible
de faire mieux ?
Et pourtant le C est le langage le plus proche de l'assembleur!
Ok dans la plupart des cas le compilo fera mieux, mais pas toujours!

Je pense qu'il n'y a pas plus mauvais conseil que de dire "N'optimisez pas
vos codes, le compilo s'en charge"
Te rends tu compte de la portée de ce que tu dis ?

++
Jean-marc
Le #16709801
Sebastien wrote:

Hello,

Hum sur un plan académique, je dirais plutot de bannir la boucle for!



C'est une question de goût, pas d'académisme. La boucle For à ses usages.

Enfin, ce que tu dis n'est pas totalement faux mais loin d'etre
totalement vrai!
Un compilo plus intelligent qu'un codeur ? je doute un peu quand meme!



Pas plus intelligent, mais capable de faire des optimisations au niveau
de la génération de l'ASM généré qui n'ont pas forcément à voir avec
le code.

Ici il faut comprendre : c'est souvent inutile d'essayer d'augmenter
la rapidité du code en faisant des astuces au niveau purement
syntaxique.

Fais un code en C, sort le listing asm et dis moi qu'il n'est pas
possible de faire mieux ?



Il est souvent difficile, si pas impossible, de faire mieux "à la main"
au niveau traduction que ce que fait un bon compilateur en utilisant
les bonnes options d'optimisation.

Et pourtant le C est le langage le plus proche de l'assembleur!
Ok dans la plupart des cas le compilo fera mieux, mais pas toujours!



On est bien d'accord :-) Mais si tu as un problème de perfs que seule
une réécriture en assembleur à la main peut résoudre, ton problème
n'est pas la ou tu crois. Cf la suite ...

Je pense qu'il n'y a pas plus mauvais conseil que de dire
"N'optimisez pas vos codes, le compilo s'en charge"
Te rends tu compte de la portée de ce que tu dis ?



Bien sur. Je dis et je répète qu'il ne faut pas essayer de soi-disant
"optimiser" en essayant des "trucs" syntaxiques du genre ne pas mettre
la variable d'index dans le Next, faire un DO/While Loop plutot qu'un For,
etc.

Je dis que ce qu'il faut optimiser, c'est la partie algorithmique de la
chose.
Par exemple :
- sortir les invariants des boucles
- Précalculer tout ce qui peut l'être
- Calculer la complexité algorithmique et remplacer par
exemple les traitemens en O(n²) par des choses en O(n) ou Log(n),
etc.

Ca passe par :
- réfléchir
- Choisir les bons algorithmes
- Choisir les bonnes structures de données
- Etc.

Exemples :
- ce n'est pas la peine d'essayer d'"optimiser" un
tri à bulles. Il est en O(n²), et c'est comme ça. Ce n'est pas en
bidouillant la syntaxe ni même en le codant en assembleur (à la main,
encore mieux que le meilleur des compilos C ...) que cet algo sera
performant. Si on doit trier de grands volumes, on choisira un meilleur
algo, par exemple Quick Sort, ou autre selon les cas.

- Pour rechercher efficacement dans un dictionnaire (non trié) comportant
des millions d'entrées, il y a des méthodes efficaces (tries/trees) et
d'autres moins, voire beaucoup moins. Le choix de l'algo est déterminant.

Ca ne veux pas dire qu'il faut coder comme un cochon, c'est précisément tout
le contraire !

Je dis qu'il faut toujours garder un code clair, sans astuces syntaxiques.
Le
compilateur fera le travail et génèrera du code bien net, dans la plupart
des
cas. Mais si on lui donne un algo faible ou lent, il produira du code
"optimisé",
mais intrinsèquement lent.

Et on a abordé ici qu'une toute petite partie de la problématique de
l'optimisation. Par exemple, il est toujours amusant de voir de jeunes
programmeurs tout fiers de venir annoncer une "optimisation" obtenue
par un bricolage immonde leur code C (rendant le code parfaitement illisible
et bourré de bugs). Dans 99,99% des cas quand on leur demande de faire le
calcul objectif du bénéfice de leur "optimisation", ils reviennent la queue
entre les jambes 2 heures après avec des conclusions du genre : "ah ben oui,
en supposant que mon programme soit utilisé en continu 12 heures par jours,
j'ai gagné en tout et pour tout 7,3 secondes, soit une magnifique
amélioration
de 0,016% ..." Super ....

Pour conclure, voici quelques articles de notre FAQ qui montrent de vraies
optimisations :

Lecure rapide de fichiers texte:
http://faq.vb.free.fr/index.php?question5
(500% de gain)

Recherche dans une liste box:
http://faq.vb.free.fr/index.php?question5


Concaténation rapide: (également utilisable en C, d'ailleurs)
http://faq.vb.free.fr/index.php?question3
(ici des gains de 1000%)

Tris, dont certains très rapides:
http://faq.vb.free.fr/index.php?question1


Validation de données complexes en remplaçant les RegExp (lentes) par
des automates à états finis (ultra rapide et portable tous langages):
http://faq.vb.free.fr/index.php?question3


Bien cordialement,

--
Jean-marc Noury (jean_marc_n2)
Microsoft MVP - Visual Basic
FAQ VB: http://faq.vb.free.fr/
mailto: remove '_no_spam_' ;
Sebastien
Le #16710511
> C'est une question de goût, pas d'académisme. La boucle For à ses usages.



Hum si on veut, mais je vois pas de cas ou un for est irremplacable ou plus
performant...


Il est souvent difficile, si pas impossible, de faire mieux "à la main"
au niveau traduction que ce que fait un bon compilateur en utilisant
les bonnes options d'optimisation.



Oui, si le code de haut niveau est construit intelligement a la base...


Et pourtant le C est le langage le plus proche de l'assembleur!
Ok dans la plupart des cas le compilo fera mieux, mais pas toujours!



On est bien d'accord :-) Mais si tu as un problème de perfs que seule
une réécriture en assembleur à la main peut résoudre, ton problème
n'est pas la ou tu crois. Cf la suite ...



La on est 100% d'accord, mais reste que dans certains cas le moindre cycle a
son importance tout algo confondu


- Pour rechercher efficacement dans un dictionnaire (non trié) comportant
des millions d'entrées, il y a des méthodes efficaces (tries/trees) et
d'autres moins, voire beaucoup moins. Le choix de l'algo est déterminant.

Ca ne veux pas dire qu'il faut coder comme un cochon, c'est précisément
tout
le contraire !

Je dis qu'il faut toujours garder un code clair, sans astuces syntaxiques.
Le



Ok, le principe est bon mais en pratique c'est comme ca que l'on se retrouve
avec des prog complètement surchargés!
Si chaque programme qui tourne sur ton pc perd une dizaine de cycles par
fonctions (c pas grand choses 10 cycles ca va très vite) juste par soucis de
lisibilité du code...

Je vais pas utiliser 4 variables genre LenTxt1, LenTxt2, LenTxt3, LenTxt4
pour que le code soit plus clair si je peux le faire avec une seule variable
genre Len
ca reste tout a fait lisible et l'économie est réelle a grande échelle.
(dans ce petit exemple on perd déjà bien plus de 10 cycles!)

Je suis néanmoins d'accord avec ton discourt mais je te trouve un peu trop
ferme.
Une astuce de syntaxe ne vaudra jamais un meilleur algo c'est certain un
code con reste un code con même optimisé, mais gâcher des cycles pour une
question de lisibilité non! Enfin après tous les langages ne sont pas égaux,
en C on a les macro et les inline qui permettent un code optimisé et lisible
sans concessions, ce n'est malheureusement pas le cas en VB...

Enfin la on s'évade, je voulais juste réagir a ce conseil de départ qui pour
moi pouvait être dangereusement interprété.
Le reste relève plus de la philo ou du cas par cas...

Sinon merci pour tes éclaircissements et ta pédagogie a toute épreuve :)
Je manquerais pas de consulter tes liens des que j'aurais une minute!

Bonne soirée
++
jean-marc
Le #16713991
"Sebastien" news:

Hello,

C'est une question de goût, pas d'académisme. La boucle For à ses usages.



Hum si on veut, mais je vois pas de cas ou un for est irremplacable ou
plus performant...



C'est tout à fait vrai. For n'est pas irremplaçable. Il est
juste des cas ou il sera 'naturel' de l'employer.
Mais tu as raison, il n'est jamais plus perfomant qu'autre
chose.


Enfin la on s'évade, je voulais juste réagir a ce conseil de départ qui
pour moi pouvait être dangereusement interprété.



C'est vrai. J'aurais du nuancer afin d'être parfaitement
clair :-)

Le reste relève plus de la philo ou du cas par cas...



Sur!

Sinon merci pour tes éclaircissements et ta pédagogie a toute épreuve :)
Je manquerais pas de consulter tes liens des que j'aurais une minute!



Ok !

Bonne soirée



Bonne journée !

Cordialement,


--
Jean-marc Noury (jean_marc_n2)
Microsoft MVP - Visual Basic
FAQ VB: http://faq.vb.free.fr/
mailto: remove '_no_spam_' ;
Driss HANIB
Le #16716651
Salut Jean Marc (et Sébastien..)

Merci pour cet échange "technique" pour le moins, même si, du fait de mon
niveau, j'aurai du mal à appliquer tous ces conseils (je vais aller lire les
FAQ citées de suite.)
En tout cas ça décrasse les méninges..
Dans la même veine , contrairement au TROLL, j'utilise autant que faire ce
peut les procédures et les fonctions.
Jusqu'à quel point faire cela est-il utile ?
je m'explique : j'utilise cela dès que je pense qu'une action sera demandée
plusieurs fois, aussi bien dans la feuille en cours que dans d'autres. Mais
aussi, lorsque dans une fonction assez "complexe" (pour moi bien sûr), je
dois rajouter un traitement lui aussi compliqué. Alors je m'arrange pour
mettre ceci dans une procédure afin de gagner en "lisibilité".
Mais perd t'on comme le dis Sebastien beaucoup de cycles ou de temps à
appeler une procédure externe ?
je ne suis pas au point de réécrire tous les algorythmes, même si cela me
prend, mais je voudrai ne pas trop perdre en efficacité..

Merci

Driss

"jean-marc" 48bf9ee9$0$2870$

"Sebastien" news:

Hello,

C'est une question de goût, pas d'académisme. La boucle For à ses
usages.



Hum si on veut, mais je vois pas de cas ou un for est irremplacable ou
plus performant...



C'est tout à fait vrai. For n'est pas irremplaçable. Il est
juste des cas ou il sera 'naturel' de l'employer.
Mais tu as raison, il n'est jamais plus perfomant qu'autre
chose.


Enfin la on s'évade, je voulais juste réagir a ce conseil de départ qui
pour moi pouvait être dangereusement interprété.



C'est vrai. J'aurais du nuancer afin d'être parfaitement
clair :-)

Le reste relève plus de la philo ou du cas par cas...



Sur!

Sinon merci pour tes éclaircissements et ta pédagogie a toute épreuve :)
Je manquerais pas de consulter tes liens des que j'aurais une minute!



Ok !

Bonne soirée



Bonne journée !

Cordialement,


--
Jean-marc Noury (jean_marc_n2)
Microsoft MVP - Visual Basic
FAQ VB: http://faq.vb.free.fr/
mailto: remove '_no_spam_' ;







Sebastien
Le #16717121
Salut DRISS,

Mais perd t'on comme le dis Sebastien beaucoup de cycles ou de temps à
appeler une procédure externe ?
je ne suis pas au point de réécrire tous les algorythmes, même si cela me
prend, mais je voudrai ne pas trop perdre en efficacité..



Eh oui on perd pas mal de temps mais tout est relatif...

Pour un appel de fonction, tu dois empiler chaque paramètres (sans compter
les copies de variable genre string en byval!) puis l'appel et ensuite le
saut de retour et le dépilement de chaque paramètres et destructions des
éventuelles variables copiées.

C'est couteux, mais on ne va pas faire tout notre prog sur une seule
procédure...
Donc il faut un juste milieu entre lisibilité et performance.
Le fait que tu appel le code dans plusieurs endroit ne doit pas justifier
l'exportation de code dans une procédure/fonction, ceci reviendrait a cocher
la case "Optimiser pour la taille du code" en défaveur des performances!
Mais ca peut tout de même être une bonne raison niveau lisibilité et temps
de dev...

C'est justement pour ca que je parlais des inline plus haut, c'est une
fonction devant laquelle tu met le mot clé "inline" et lors de la
compilation le compilo va remplacer l'appel de chaque fonction par le code
que contient la fonction, donc en gros dans le code tu vois un appel, mais
une fois compilé il n'y a plus d'appel la fonction a été fusionnée dans la
fonction appelante..
Malheureusement pas possible en vb du moins nativement, mais il est possible
de faire un addin qui ferait la même chose, ca doit même surement déjà
exister...

++
Publicité
Poster une réponse
Anonyme