Je vois souvent des questions relatives à Overflow
erreurs avec vba .
Ma question est la suivante: pourquoi utiliser la déclaration de variable integer
au lieu de simplement définir toutes les variables numériques (à l’exclusion de double
etc.) comme long
?
Sauf si vous effectuez une opération comme dans une boucle for où vous pouvez garantir que la valeur ne dépassera pas la limite de 32 767, existe-t-il un impact sur les performances ou sur quelque chose d'autre qui imposerait de ne pas utiliser long
?
Les variables entières sont stockées sous forme de nombres de 16 bits (2 octets)
Les variables longues (entier long) sont stockées sous forme de nombres signés 32 bits (4 octets)
L’avantage est donc de réduire l’espace mémoire. Un entier occupe la moitié de la mémoire d'un long. Maintenant, nous parlons de 2 octets, donc cela ne changera rien si vous ne stockez pas une tonne d'entiers.
[~ # ~] mais [~ # ~] sur un = 32 système de bits, un entier de 16 bits est converti silencieusement en long sans le bénéfice de la plus grande gamme de nombres avec laquelle travailler. Les débordements se produisent toujours et cela prend tout autant de mémoire. La performance peut même être blessée car le type de données doit être converti (à très niveau faible).
Pas la référence que je cherchais mais ....
D'après ce que je comprends, le moteur sous-jacent VB convertit les entiers en long même s'il est déclaré comme un entier. Par conséquent, une légère diminution de la vitesse peut être constatée. Je le crois depuis un certain temps et peut-être aussi pourquoi la déclaration ci-dessus a été faite, je n'ai pas demandé de raisonnement.
C'est la référence que je cherchais.
Réponse courte, dans les systèmes 32 bits, les entiers sur 2 octets sont convertis en éléments longs sur 4 octets. Il n'y a vraiment pas d'autre moyen pour que les bits respectifs s'alignent correctement pour toute forme de traitement. Considérer ce qui suit
MsgBox Hex(-1) = Hex(65535) ' = True
Évidemment, -1 n’est pas égal à 65535, mais l’ordinateur renvoie la bonne réponse, à savoir "FFFF" = "FFFF"
Cependant, si nous avions contraint le -1 à un long début, nous aurions obtenu la bonne réponse (65535 étant supérieur à 32k est automatiquement long)
MsgBox Hex(-1&) = Hex(65535) ' = False
"FFFFFFFF" = "FFFF"
En général, il est inutile dans VBA de déclarer "As Integer" dans les systèmes modernes, sauf peut-être pour certaines API héritées qui s'attendent à recevoir un Integer.
Et enfin, j'ai trouvé le documentation msdn que je cherchais vraiment.
Traditionnellement, les programmeurs VBA utilisaient des entiers pour contenir de petits nombres, car ils nécessitaient moins de mémoire. Dans les versions récentes, cependant, VBA convertit toutes les valeurs entières en type Long, même si elles sont déclarées en tant que type Integer. Il n’ya donc plus d’avantage en termes de performances pour utiliser les variables Integer; En fait, les variables longues peuvent être légèrement plus rapides car VBA n'a pas à les convertir.
Donc, en résumé, il n’ya presque aucune bonne raison d’utiliser un type Integer
de nos jours. Sauf si vous devez interagir avec un ancien appel d'API qui attend un int de 16 bits.
Il convient de souligner que certaines anciennes fonctions de l'API peuvent attendre des paramètres d'entiers 16 bits (2 octets) et si vous utilisez un 32 bits et essayez de passer un entier (celui-ci est déjà long de 4 octets). par référence, cela ne fonctionnera pas à cause de la différence de longueur en octets.
Merci à Vba4All de nous l'avoir signalé.
Comme indiqué dans d'autres réponses, la vraie différence entre int et long est la taille de son espace mémoire et donc la taille du nombre qu'il peut contenir.
voici la documentation complète sur ces types de données http://msdn.Microsoft.com/en-us/library/office/ms474284 (v = office.14) .aspx
un entier représente 16 bits et peut représenter une valeur comprise entre -32 768 et 32 767
a Long correspond à 32 bits et peut représenter -2 147 483 648 à 2 147 483 647
et il y a un LongLong qui est 64 bits et peut gérer comme 9 pentilion
Une des choses les plus importantes à retenir est que les types de données diffèrent par la langue et par le système d’exploitation. Dans votre monde de VBA, 32 bits sont longs, mais en c # sur un processeur 64 bits, 64 bits sont longs. Cela peut introduire une confusion importante.
Bien que VBA ne le supporte pas, lorsque vous passez à une autre langue, que ce soit en .net ou Java ou autre), je préfère de loin utiliser les types de données système de int16 , int32 et int64 , ce qui me permet d’être beaucoup plus transparent sur les valeurs pouvant être conservées dans ces types de données.
VBA a beaucoup de bagages historiques.
Un Integer
a une largeur de 16 bits et était un bon type numérique par défaut lorsque l'architecture et les tailles de mots 16 bits étaient répandues.
Un Long
a une largeur de 32 bits et (IMO) doit être utilisé autant que possible.
Bien que ce poste date de quatre ans, j'étais curieux à ce sujet et j'ai effectué quelques tests. La chose la plus importante à noter est qu’un codeur devrait TOUJOURS déclarer une variable SOMMAIRE. Les variables non déclarées ont manifestement affiché la pire performance (non déclarées techniquement Variant
)
Long
a été le plus rapide, je dois donc penser que la recommandation de Microsoft de toujours utiliser Long
au lieu de Integer
a un sens. Je devine la même chose que true avec Byte
, mais la plupart des codeurs ne l'utilisent pas.
RESULTATS SUR ORDINATEUR PORTABLE WINDOWS 10 BITS
Code utilisé:
Sub VariableOlymics()
'Run this macro as many times as you'd like, with an activesheet ready for data
'in cells B2 to D6
Dim beginTIME As Double, trials As Long, i As Long, p As Long
trials = 1000000000
p = 0
beginTIME = Now
For i = 1 To trials
Call boomBYTE
Next i
Call Finished(p, Now - beginTIME, CDbl(trials))
p = p + 1
beginTIME = Now
For i = 1 To trials
Call boomINTEGER
Next i
Call Finished(p, Now - beginTIME, CDbl(trials))
p = p + 1
beginTIME = Now
For i = 1 To trials
Call boomLONG
Next i
Call Finished(p, Now - beginTIME, CDbl(trials))
p = p + 1
beginTIME = Now
For i = 1 To trials
Call boomDOUBLE
Next i
Call Finished(p, Now - beginTIME, CDbl(trials))
p = p + 1
beginTIME = Now
For i = 1 To trials
Call boomUNDECLARED
Next i
Call Finished(p, Now - beginTIME, CDbl(trials))
p = p + 1
End Sub
Private Sub boomBYTE()
Dim a As Byte, b As Byte, c As Byte
a = 1
b = 1 + a
c = 1 + b
c = c + 1
End Sub
Private Sub boomINTEGER()
Dim a As Integer, b As Integer, c As Integer
a = 1
b = 1 + a
c = 1 + b
c = c + 1
End Sub
Private Sub boomLONG()
Dim a As Long, b As Long, c As Long
a = 1
b = 1 + a
c = 1 + b
c = c + 1
End Sub
Private Sub boomDOUBLE()
Dim a As Double, b As Double, c As Double
a = 1
b = 1 + a
c = 1 + b
c = c + 1
End Sub
Private Sub boomUNDECLARED()
a = 1
b = 1 + a
c = 1 + b
c = c + 1
End Sub
Private Sub Finished(i As Long, timeUSED As Double, trials As Double)
With Range("B2").Offset(i, 0)
.Value = .Value + trials
.Offset(0, 1).Value = .Offset(0, 1).Value + timeUSED
.Offset(0, 2).FormulaR1C1 = "=ROUND(RC[-1]*3600*24,0)"
End With
End Sub
Ceci est un problème espace vs nécessité.
Dans certaines situations, c'est un nécessité d'utiliser un long. Si vous parcourez des lignes dans un fichier Excel volumineux, la variable contenant le numéro de ligne doit être longue.
Cependant, vous saurez parfois qu'un nombre entier peut gérer votre problème et utiliser un long serait un gaspillage de espace (mémoire). Les variables individuelles ne font vraiment pas une grande différence, mais quand vous commencez à manipuler des tableaux, cela peut faire une grande différence.
Dans VBA7, les entiers sont 2 octets et longs sont 4 octets
Si vous avez un tableau de 1 million de nombres compris entre 1 et 10, utiliser un tableau Integer prendrait environ 2 Mo de RAM, contre environ 4 Mo de = RAM pour un tableau long.
J'ai pris la méthode de @ PGSystemTester et je l'ai mise à jour pour supprimer certaines variabilités potentielles. En plaçant la boucle dans les routines, cela supprime le temps nécessaire pour appeler la routine (ce qui prend beaucoup de temps). J'ai également désactivé la mise à jour de l'écran pour supprimer les retards éventuels.
Long
a tout de même obtenu les meilleurs résultats, et comme ces résultats se limitent davantage aux impacts des types de variables uniquement, il convient de noter l'ampleur de la variation.
Mes résultats (bureau, Windows 7, Excel 2010):
Code utilisé:
Option Explicit
Sub VariableOlympics()
'Run this macro as many times as you'd like, with an activesheet ready for data
'in cells B2 to D6
Dim beginTIME As Double, trials As Long, i As Long, p As Long
Dim chosenWorksheet As Worksheet
Set chosenWorksheet = ThisWorkbook.Sheets("TimeTrialInfo")
Application.EnableEvents = False
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
trials = 1000000000 ' 1,000,000,000 - not 10,000,000,000 as used by @PGSystemTester
p = 0
beginTIME = Now
boomBYTE trials
Finished p, Now - beginTIME, CDbl(trials), chosenWorksheet.Range("B2")
p = p + 1
beginTIME = Now
boomINTEGER trials
Finished p, Now - beginTIME, CDbl(trials), chosenWorksheet.Range("B2")
p = p + 1
beginTIME = Now
boomLONG trials
Finished p, Now - beginTIME, CDbl(trials), chosenWorksheet.Range("B2")
p = p + 1
beginTIME = Now
boomDOUBLE trials
Finished p, Now - beginTIME, CDbl(trials), chosenWorksheet.Range("B2")
p = p + 1
beginTIME = Now
boomUNDECLARED trials
Finished p, Now - beginTIME, CDbl(trials), chosenWorksheet.Range("B2")
p = p + 1
Application.EnableEvents = True
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
chosenWorksheet.Calculate
End Sub
Private Sub boomBYTE(numTrials As Long)
Dim a As Byte, b As Byte, c As Byte
Dim i As Long
For i = 1 To numTrials
a = 1
b = 1 + a
c = 1 + b
c = c + 1
Next i
End Sub
Private Sub boomINTEGER(numTrials As Long)
Dim a As Integer, b As Integer, c As Integer
Dim i As Long
For i = 1 To numTrials
a = 1
b = 1 + a
c = 1 + b
c = c + 1
Next i
End Sub
Private Sub boomLONG(numTrials As Long)
Dim a As Long, b As Long, c As Long
Dim i As Long
For i = 1 To numTrials
a = 1
b = 1 + a
c = 1 + b
c = c + 1
Next i
End Sub
Private Sub boomDOUBLE(numTrials As Long)
Dim a As Double, b As Double, c As Double
Dim i As Long
For i = 1 To numTrials
a = 1
b = 1 + a
c = 1 + b
c = c + 1
Next i
End Sub
Private Sub boomUNDECLARED(numTrials As Long)
Dim a As Variant, b As Variant, c As Variant
Dim i As Long
For i = 1 To numTrials
a = 1
b = 1 + a
c = 1 + b
c = c + 1
Next i
End Sub
Private Sub Finished(i As Long, timeUSED As Double, trials As Double, initialCell As Range)
With initialCell.Offset(i, 0)
.Value = trials
.Offset(0, 1).Value = timeUSED
.Offset(0, 2).FormulaR1C1 = "=ROUND(RC[-1]*3600*24,2)"
End With
End Sub
Comme d’autres déjà mentionné, un Long peut occuper deux fois plus d’espace qu'un Integer. Comme d'autres l'ont déjà mentionné, la capacité élevée des ordinateurs actuels signifie que vous verrez aucune différence de performances, sauf si vous traitez des quantités de données extrêmement importantes:
Considérant que 1 million de valeurs, la différence entre utiliser des entiers et des longs serait de 2 octets pour chaque valeur, de sorte que 2 * 1 000 000/1024/1024 = moins de 2 Mo de différence dans votre RAM, qui est probablement beaucoup moins que 1% ou même 0,1% de votre RAM capacité.
Si l'on se base sur le repère réalisé par PGSystemTester, vous pouvez constater une différence de 811 à 745 = 66 secondes entre les longueurs longue et entière, lorsque 10 milliards de lots de 4 opérations sont traités. Réduisez le nombre à 1 million d'opérations et nous pouvons nous attendre à 66/10 000/4 = moins de 2 ms de différence de temps d'exécution.
J'utilise personnellement Integer et Longs to lisibilité de mon code, en particulier dans les boucles, où Un entier indique que la boucle devrait être petite (moins de 1000 itérations), alors qu'un long me dit que la boucle est devrait être assez grand (plus de 1000).
Notez que ce seuil subjectif est bien inférieur à la limite supérieure Integer. J'utilise Longs uniquement pour faire la distinction entre mes propres définitions de petit et grand.