us_30
Messages postés2065Date d'inscriptionlundi 11 avril 2005StatutMembreDernière intervention14 mars 2016
-
28 janv. 2006 à 17:15
us_30
Messages postés2065Date d'inscriptionlundi 11 avril 2005StatutMembreDernière intervention14 mars 2016
-
31 janv. 2006 à 01:05
Bonjour,
Dans mes petites recherches pour l'optimisation dexécution en VBA, je viens de tomber sur une énigme... (Javais déjà déposé un petit tuto sur VBF sur le sujet, qui se trouve maintenant sur mon modeste site )
En effet, je me suis intéressé aux types de variables dans un calcul. Lidée était de classer en fonction de la vitesse dexécution, les différents types de variables, suite à un calcul dune expression Naturellement, je pensais que le type Long était normalement le plus rapide que Double Ceci est correctement vérifier pour lexécution dune boucle comme avec FOR TO NEXT Et en effet, cest la même chose, si dans un lexpression dun calcul, toutes les variables sont du type LONG, par rapport à DOUBLE (quoique assez faible ).
MAIS là, où je reste le cul par terre ! (excusez moi de lexpression), cest que suite à une erreur de manipulation, jai découvert quune combinaison (un peu savante) du type Long et Double, donne un calcul plus rapide !
Jai testé de nombreuses fois le phénomène, sur 2 PC, sous Excel 97 et 2003 et même constat JE suis vraiment stupéfait ! Qui en connaît une explication rationnelle ?
=
Le code des tests (un peu simplifié) donnent ceci :
Sub test()
Dim t As Long, t2 As Long, duree As Double, temps As Double
Dim a As Long, b As Long, c As Double, r As Double
'Dim a As Long, b As Long, c As Long, r As Long
'Dim a As Double, b As Double, c As Double, r As Double
'Dim a As Long, b As Long, c As Long, r As Double
b = 3
a = 3
c = 2
For t2 = 1 To 10
temps = Timer
For t = 1 To 10000000
r = a * b * c
Next t
duree = duree + Timer - temps
Next t2
MsgBox duree / 10
End Sub
=
QUELQUES résultats après classement :
r,
a,
B,
c,
temps,
----
double,
double,
Long,
long,
2,9,
----
double,
long,
Double,
double,
3,09,
----
long,
long,
Long,
long,
3,56,
----
double,
double,
Double,
double,
3,64,
----
double,
long,
Long,
long,
3,84,
----
long,
double,
Double,
double,
4,4
ET comme on peut le constater, les deux plus rapides sont un mélange de type ! ! Curieux, non ? !
Jai aussi un peu regardé avec les 3 autres opérations élémentaires, et idem JE ne sais pas si dans VB après compilation, cela donne les mêmes résultats, puisque ce qui mintéresse cest lexécution sous Excel, donc en VBA (mode interprété, du fait)
Evidemment comprendre comment cela se fait, pourra aidé à trouver le meilleur type pour les variables, en vue dune optimisation fine
Amicalement,
Us.
PS : On peut utiliser autre chose que TIMER mais cela ne change absolument rien en moyenne aux résultats (Merci de ne pas rentrer dans ce débat totalement stérile et sans fondement...)
kalobit
Messages postés169Date d'inscriptionmardi 15 juillet 2003StatutMembreDernière intervention 7 avril 20082 30 janv. 2006 à 11:51
Bha, c'est peut être que tout le monde colle.
Je vais essayer d'avancer une explication. Je précise bien que je pars sur des supposition. Toutefois, si quelqu'un arrive à prouver ce que j'avance, ça me ferait plaisir.
Tout d'abord :
Voici mes résultats triés en ordre croissant de rapidité
<COLGROUP>
<COL span=5 width=80>
----
R,
a,
b,
c,
Temps,
----
Long,
Long,
Long,
Long,
3,92434375,
----
Double,
Double,
Double,
Double,
4,46434375,
----
Double,
Long,
Double,
Double,
4,82946875,
----
Double,
Long,
Long,
Double,
5,458625,
----
Double,
Long,
Long,
Long,
5,972125,
----
Long,
Double,
Double,
Double,
6,3810625,
----
Long,
Long,
Double,
Double,
6,59,
----
Long,
Long,
Long,
Double,
7,807
Voici ce que j'en tire
Principe 1 :
Le long est plus rapide que le double. Forcément, 4 octets contre 8, ça ne se discute pas
Principe 2 :
Le traitement avec un seul type de variable est plus rapide que le même traitement avec plusieurs type de variable
Principe 3 :
Le résultat d'un traitement de plusieurs type de variable est plus rapide si on lui affecte le type de la variable la plus grande (en espace mémoire)
Il faut donc comprendre qu'un résultat Double de variables double et long est plus rapide qu'un résultat long de variables double et long
Voilà pour les principes qui pour moi semblent clairs. Je vais maintenant pousser le raisonnement un peu plus loin.
La conversion temporaire.
Pour effectuer le calcul, il faut que les variables soient du même type. On va donc convertir les variables dans le type le plus grand (pour ce qui nous interrese, ce sera toujours de long - 4octets - à Double - 8 octets)
Enfin pour donner le résultat, on va reconvertir toutes les variables dans le type du résultat.
Ce qui donne, dans le même ordre que mes résultats
<COLGROUP>
<COL span=15 width=25>
<COL width=59>
----
R,
a,
b,
c,
,
">->,
a,
b,
c,
,
">->,
a,
b,
c,
,
Nb Conv,
----
L,
L,
L,
L,
,
,
L,
L,
L,
,
,
L,
L,
L,
,
0,
----
D,
D,
D,
D,
,
,
D,
D,
D,
,
,
D,
D,
D,
,
0,
----
D,
L,
D,
D,
,
,
D,
D,
D,
,
,
D,
D,
D,
,
1,
----
D,
L,
L,
D,
,
,
D,
D,
D,
,
,
D,
D,
D,
,
2,
----
D,
L,
L,
L,
,
,
L,
L,
L,
,
,
D,
D,
D,
,
3,
----
L,
D,
D,
D,
,
,
D,
D,
D,
,
,
L,
L,
L,
,
3,
----
L,
L,
D,
D,
,
,
D,
D,
D,
,
,
L,
L,
L,
,
4,
----
L,
L,
L,
D,
,
,
D,
D,
D,
,
,
L,
L,
L,
,
5
J'ai noté en rouge les conversions de type.
Voici les explications pour les lignes 5 à 8
Ligne 5 :
Le type dominant du calcul est L, pas de conversion
Le type du résultat est D on converti 3 L en D
Total 3 Conversions.
Ligne 6
Le type dominant du calcul est D, pas de conversion ( déjà 3D)
Le type du résultat est L, on converti 3D en L
Total 3 conversion
Ici on note sur les lignes 5 et 6 le même nombre de conversion alors que 5 est plus rapide que 6.
L'explication que je donne est que la conversion L -> D est plus rapide. Et pour cause, on passe de 4 à 8 octets, ce qui semble plus simple que l'inverse.
Ligne 7 :
Le type dominant du calcul est D, on converti 1 L en D
Le type du résultat est L, on converti 3 D en L
Total 4 conversions
Ligne 8 :
Le type dominant du calcl est D, on converti 2L en D
Le type du résultat est L, on converti 3L en D
Total 5 conversions.
En comparant donc la rapidité du code avec d'une part les 3 principes énoncés et d'autre part mon théorème sur les conversions, j'en arrive à la conclusion suivante.
Pour optimiser la rapidité de son code, on favorisera dans ses calculs un seul type de données, si possible celui monopolisant le moins de mémoire possible. Si ce n'est pas possible, on attribuera à la variable résultat le type de donnée le plus fort par mis les variables du calcul.
Par exemple, avec trois variables de calcul (1 long et 2 double), le résultat en double sera plus rapide à calculer que le résultat en long. Idem si 2 long et 1 double.
kalobit
Messages postés169Date d'inscriptionmardi 15 juillet 2003StatutMembreDernière intervention 7 avril 20082 30 janv. 2006 à 13:53
j'oubliais un petit détail,
J'ai utilisé la notion de "variable dominante" qui porte à confusion. Il fallait bien comprendre la variable qui utilise le plus de mémoire. Donc on converti le long en double et pas le double en long
Mais bon c'est clair que ce ne sont pas là des vérités verrifiées et approuvées.
Je tiens juste à faire une remarque très importante. où est l'interêt de place le résultat d'un produit d'un long et d'un double dans un long.
la logique veut que ce soit forcément un double car sinon on risque un dépassement de capacité.
Donc la règle découlant de tout ça c'est :
Toujours attribuer au résultat le type de la variable la plus grande!!!
Ici, on s'est arrêter à des variable de valeur 10*10^6. Mais si on va au delà, le long ne suit pas et se trouve contraint à utiliser des doubles.
Pour finir sur les convertions, je vous invite à tester ces deux routines :
la première converti les long en double et la deuxième fait l'inverse.
Je vous laisse interpréter les résultats. chez moi
0,3789063 L2D
0,6835938 D2L
Sub testerconvL2D()
Dim temps
Dim départ
Dim fin
Dim x As Long
Dim y As Double
départ = Timer
For x = 1 To 10000000
y = CDbl(x)
Next
fin = Timer
temps = fin - départ
Debug.Print temps
End Sub
Sub testerconvD2L()
Dim temps
Dim départ
Dim fin
Dim x As Long
Dim y As Double
départ = Timer
For y = 1 To 10000000
x = CLng(y)
Next
fin = Timer
temps = fin - départ
Debug.Print temps
End Sub
[mailto:K@lobit K@lobit] <- ne pas clicker ici !!!
us_30
Messages postés2065Date d'inscriptionlundi 11 avril 2005StatutMembreDernière intervention14 mars 201610 31 janv. 2006 à 01:05
Bonsoir à tous,
Je vous remercie tous les deux de vous pencher sur ma colle , et plus particulièrement Kalobit d'avoir pris autant de temps pour faire des tests...
JE suis d'accord avec Kalobit sur ses explications qu'il expose la première fois... c'est du moins, ce que je pensais avant... mais voilà mon problème c'est qu'en refaissant encore mes tests exposés, j'obtiens bien des meilleurs résultats avec : r en double, a en double, b en long et c en long ! Meilleur que si toutes les variables étaient en Long par exemple.
Donc, là je suis en contradiction manifeste avec les tests de Kalobit. En effet, ses tests donnent un classement qui sont bien ordonnées avec ce qu'on peut penser sur la manière dont sont traités les calculs... Donc, là je ne comprends pas déjà comment se fait-il qu'on ait pas (peu ou prou) le même classement. Je ne comprends pas cette différence d'autant que j'ai pris soin de faire de nombreux tests avec deux PC, deux versions d'Excel sur deux OS différents (WinME et XP), ce qui retir quasiment toute possibilité d'un fonctionnement spécifique à une machine... Ce que j'ai exposé devrait être pareil pour tout le monde. Donc, si j'essaye d'analyser pourquoi cette différence, la seule raison simple que je vois, c'est que Kalobit n'aurait peut-être pas fait ses tests à partir de VBA, mais peut-être avec VB6... L'autre soin particulier à mes tests, qui fait écho à la remarque Gobillot de faire attention à de trop petites différences, c'est justement d'augmenter le nombre de tests dans la boucle, pour observer que la différence augmente proportionnellement. En d'autre terme en augmentant de 10 fois le nombre de passage dans la boucle FOR t= ..., j'obtiens effectivement une durée 10 fois supérieure quel que soit le test considéré. Donc les différences extrêmes (par exemple) ne sont plus de 4,4-2,9=1,5 seconde mais bien de 15 secondes; valeur bien significative. Effectivement après compilation, le classement a de fortes chances d'être plus proche de ceux de Kalobit, mais je parle bien de VBA, et il n'y a pas de compilation possible dans ce cas...
Pour revenir au dernier post de Kalobit, j'ai testé les deux procédures. J'ai obtenu
2,085938 L2D
4,007813 D2L
Résultats en tout point comparables, puisqu'on observe que les rapports des deux sont presque les mêmes : 1,9 contre 1,8...
De plus, en retirant les fonctions de convertions CLng et CDbl, donc en "forçant" une convertion de type en interne, cela ne change absolument rien aux résultats... (on aura noté que y et x sont déclarés avec Dim en Double et en Long)... Preuve (ou quasi preuve) que le principe 3 (très clairs, au passage) est justifié.
Pour le principe 1, à savoir que "Le long est plus rapide que le double" est aussi vérifié dans les résultats que j'ai exposé, et semble général. Avec cette précaution en plus, à condition que toute l'expression soit tout en Long ou tout en Double.
Par contre le principe 2... " Le traitement avec un seul type de variable est plus rapide que le même traitement avec plusieurs type de variable. " n'est pas vérifié sous VBA , chez moi.
Bon, avant d'aller vraiment plus loin il est important de voir si mes tests sont confirmés sous VBA.
Car, j'ai poursuivis un peu cette étrange comportement que j'observe et que je me n'explique pas... il est vrai cette fois (et pour le moment) que sur 1 seul PC, mais mon constat pose encore une nouvelle belle colle ! ... et j'suis de nouveau tombé sur le cul, d'ailleurs...
De fils en aiguille, j'ai repris le test proposé, mais cette fois avec 5 variables pour voir comment la vitesse se comporte, en fonction des types... ce qui m'a permis de faire cette conclusion (provisoire) ; qu'il faut que dans l'expression que toutes les variables soient en Double sauf une en Long. ET surtout, l'emplacement de cette variable en Long doit être juste après l'égalité !! J'ai observé que la position avait une importance aussi sur la vitesse, et en rien négligeable !! J'avoue perdre mon latin dans l'histoire... j'ai juste qlq spéculations, mais le plus important c'est que les résultats soient confirmés par d'autres...
Voici le test où j'ai augmenté le nb de passage par 10 pour avoir une différence significative sans discussion possible :
=
Sub test()
Dim t As Long, duree As Double, temps As Double
Dim r As Double
'Dim a As Double, b As Double, c As Double, d As Double, e As Double '44,8699951171875
Dim a As Long, b As Double, c As Double, d As Double, e As Double '37,949912109375
'Dim a As Double, b As Long, c As Double, d As Double, e As Double '46,1300585937502
'Dim a As Double, b As Double, c As Long, d As Double, e As Double '47,4100976562499
'Dim a As Double, b As Double, c As Double, d As Long, e As Double '50,259970703125
'Dim a As Double, b As Double, c As Double, d As Double, e As Long '47,9499023437502
b = 2
a = 3
c = 5
d = 7
e = 11
temps = Timer
For t = 1 To 100000000
r = a * b * c * d * e
Next t
duree = duree + Timer - temps
Debug.Print duree
End Sub
=
J'ai mis les durées en seconde en Remarque dans le code. Chaque test à été effectué 3 fois de suite, et un peu au hasard en complément...
Si au lieu de déclarer en Long une variable précise avec Dim, on déplace la variable en Long dans l'expression de "r", on obtiens des résultats comparables... donc c'est bien la position dans l'expression qui est importante... la plus mauvaise place étant l'avant-dernière...
Voilà, encore un peu d'eau au moulin, mais j'arrive de moins en moins à comprendre la logique sous-jacente lorsque VBA exécute un code