¿Por qué utilizar números enteros en lugar de largos?
A menudo veo preguntas relacionadas con Overflow
errores convba.
Mi pregunta es ¿por qué utilizar la integer
declaración de variables en lugar de simplemente definir todas las variables numéricas (excluyendo, double
etc.) como long
?
A menos que esté realizando una operación como en un bucle for donde puede garantizar que el valor no excederá el límite de 32,767, ¿hay algún impacto en el rendimiento o algo más que imponga no usar long
?
Las variables enteras se almacenan como números de 16 bits (2 bytes)
Referencia de Office VBA
Las variables largas (entero largo) se almacenan como números de 32 bits (4 bytes) con signo.
Referencia de Office VBA
Entonces, el beneficio está en la reducción del espacio de memoria. Un número entero ocupa la mitad de la memoria que un número largo. Ahora, estamos hablando de 2 bytes, por lo que no hará una diferencia real para los enteros individuales, solo es una preocupación cuando se trata de TONELADAS de enteros (por ejemplo, matrices grandes) y el uso de la memoria es crítico.
PERO en un sistema de 32 bits, el uso de memoria reducido a la mitad tiene un costo de rendimiento. Cuando el procesador realmente realiza algún cálculo con un entero de 16 bits (por ejemplo, incrementando un contador de bucle), el valor se convierte silenciosamente a un Long temporal sin el beneficio de un rango más amplio de números con los que trabajar. Todavía se producen desbordamientos y el registro que utiliza el procesador para almacenar los valores para el cálculo ocupará la misma cantidad de memoria (32 bits) en ambos sentidos. El rendimiento puede incluso verse afectado porque el tipo de datos debe convertirse (a un nivel muy bajo).
No es la referencia que estaba buscando pero....
Tengo entendido que el motor VB subyacente convierte números enteros en largos incluso si se declara como un número entero. Por lo tanto se puede notar una ligera disminución de la velocidad. He creído esto durante algún tiempo y quizás también por eso se hizo la afirmación anterior, no pedí razonamiento.
foros de ozgrid
Esta es la referencia que estaba buscando.
Respuesta corta: en sistemas de 32 bits, los números enteros de 2 bytes se convierten en largos de 4 bytes. Realmente no hay otra manera de que los bits respectivos se alineen correctamente para cualquier forma de procesamiento. Considera lo siguiente
MsgBox Hex(-1) = Hex(65535) ' = True
Obviamente -1 no es igual a 65535, pero la computadora devuelve la respuesta correcta, es decir, "FFFF" = "FFFF".
Sin embargo, si hubiéramos forzado el -1 a largo primero, habríamos obtenido la respuesta correcta (el 65535, que es mayor que 32k, es automáticamente largo)
MsgBox Hex(-1&) = Hex(65535) ' = False
"FFFFFFFF" = "FFFF"
Generalmente, en VBA no tiene sentido declarar "Como entero" en los sistemas modernos, excepto quizás para algunas API heredadas que esperan recibir un entero.
foro de revisión de pcreview
Y por fin encontré la documentación de msdn que realmente estaba buscando.
Tradicionalmente, los programadores de VBA han utilizado números enteros para contener números pequeños porque requerían menos memoria. Sin embargo, en versiones recientes, VBA convierte todos los valores enteros al tipo Long, incluso si están declarados como tipo Integer. Por lo tanto, ya no existe una ventaja de rendimiento al usar variables enteras; de hecho, las variables largas pueden ser un poco más rápidas porque VBA no tiene que convertirlas.
Para aclarar en base a los comentarios: los números enteros aún requieren menos memoria para almacenarse: una gran variedad de números enteros necesitará significativamente menos RAM que una matriz larga con las mismas dimensiones (casi exactamente la mitad, lo que puede verificar usted mismo en el Administrador de tareas) . Pero debido a que el procesador necesita trabajar con fragmentos de memoria de 32 bits, VBA convierte números enteros en largos temporalmente cuando realiza cálculos.
Entonces, en resumen, casi no hay una buena razón para usar un Integer
tipo en estos días. A menos que necesite interoperar con una llamada API antigua que espera un int de 16 bits, o que esté trabajando con grandes conjuntos de enteros pequeños y la memoria sea escasa.
Una cosa que vale la pena señalar es que algunas funciones API antiguas pueden esperar parámetros que son enteros de 16 bits (2 bytes) y si está en 32 bits e intenta pasar un entero (que ya tiene 4 bytes de longitud) por referencia no funcionará debido a la diferencia en la longitud de los bytes.
Gracias a Vba4All por señalarlo.
Aunque esta publicación tiene cuatro años, tenía curiosidad y realicé algunas pruebas. Lo más importante a tener en cuenta es que un codificador SIEMPRE debe declarar una variable como ALGO . Las variables no declaradas claramente tuvieron el peor desempeño (las no declaradas son técnicamente Variant
)
Long
funcionó más rápido, así que tengo que pensar que la recomendación de Microsoft de usar siempre Long
en lugar de Integer
tiene sentido. Supongo que ocurre lo mismo con Byte
, pero la mayoría de los codificadores no usan esto.
RESULTADOS EN PORTÁTIL WINDOWS 10 DE 64 BITS
Código utilizado:
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