integer - descripcion - ¿Por qué usar entero en lugar de largo?
meta title y meta descripcion (7)
A menudo veo preguntas relacionadas con errores de
Overflow
con
vba
.
Mi pregunta es ¿por qué usar la declaración de variable
integer
lugar de solo definir todas las variables numéricas (excluyendo
double
etc.)
long
tanto
long
?
A menos que esté realizando una operación como en un bucle for donde puede garantizar que el valor no superará el límite de 32,767, ¿hay un impacto en el rendimiento o alguna otra cosa que dicte que no se use
long
?
Las variables enteras se almacenan como números de 16 bits (2 bytes)
Las variables largas (enteros largos) se almacenan como números con signo de 32 bits (4 bytes)
Entonces, el beneficio está en un espacio de memoria reducido. Un número entero ocupa la mitad de la memoria que un largo hace. Ahora, estamos hablando de 2 bytes, por lo que no va a hacer una diferencia real a menos que esté almacenando una TONELADA de enteros.
PERO en un sistema de 32 bits, un entero de 16 bits se convierte silenciosamente en un largo sin el beneficio del mayor rango de números para trabajar. Todavía se producen desbordamientos y se necesita la misma cantidad de memoria. El rendimiento incluso puede 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 enteros en largos incluso si se declara como un entero. Por lo tanto, se puede observar una ligera disminución de la velocidad. He creído esto por algún tiempo y quizás por eso también se hizo la declaración anterior, no pedí razonamiento.
Esta es la referencia que estaba buscando.
Respuesta corta, en los sistemas de 32 bits, los enteros de 2 bytes se convierten en longitudes de 4 bytes. Realmente no hay otra manera para 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 está devolviendo la respuesta correcta, a saber, "FFFF" = "FFFF"
Sin embargo, si hubiéramos forzado el -1 a un largo primero, habríamos obtenido la respuesta correcta (el 65535 es mayor que 32k es automáticamente un largo)
MsgBox Hex(-1&) = Hex(65535) '' = False
"FFFFFFFF" = "FFFF"
En general, no tiene sentido que VBA declare "As Integer" en los sistemas modernos, excepto quizás por algunas API heredadas que esperan recibir un Integer.
Y por fin encontré la documentación de msdn que realmente estaba buscando.
Tradicionalmente, los programadores de VBA han usado números enteros para contener números pequeños, ya que requieren menos memoria. Sin embargo, en versiones recientes, VBA convierte todos los valores enteros a tipo Long, incluso si se declaran como tipo Integer. Por lo tanto, ya no hay 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.
Entonces, en resumen, casi no hay una buena razón para usar un tipo
Integer
estos días.
A menos
que necesite interoperar con una antigua llamada de API que espera un int de 16 bits.
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 un bit de 32 y está tratando de pasar un entero (que ya tiene una longitud de 4 bytes) por referencia no funcionará debido a la diferencia en la longitud de bytes.
Gracias a Vba4All por señalar eso.
Aunque esta publicación tiene cuatro años, tenía curiosidad sobre esto 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 tuvieron claramente el peor desempeño (las no declaradas son técnicamente
Variant
)
Long
tuvo el mejor desempeño, así que tengo que pensar que la recomendación de Microsoft de usar siempre
Long
lugar de
Integer
tiene sentido.
Supongo que lo mismo es cierto con
Byte
, pero la mayoría de los codificadores no usan esto.
RESULTADOS EN LA COMPUTADORA PORTÁTIL DE 64 BITS WINDOWS 10
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
Como otros ya mencionaron, un Long puede ocupar el doble de espacio que un Integer . Como otros también ya mencionaron, la alta capacidad de las computadoras actuales significa que no verá ninguna diferencia en el rendimiento , a menos que esté tratando con cantidades extra extra extra de datos:
Memoria
Considerando 1 millón de valores , la diferencia entre usar números enteros versus largos sería de 2 bytes para cada valor, por lo que es 2 * 1 000 000 / 1,024 / 1024 = menos de 2 MB de diferencia en su RAM , lo que probablemente sea mucho menor que 1% o incluso 0.1% de su capacidad de RAM.
Tratamiento
Teniendo en cuenta el punto de referencia realizado por PGSystemTester''s, puede ver una diferencia de 811 - 745 = 66 segundos entre Longs y Integers, al procesar 10 mil millones de lotes de 4 operaciones cada uno. Reduzca el número a 1 millón de operaciones y podemos esperar 66/10 000/4 = menos de 2 ms de diferencia en el tiempo de ejecución .
Personalmente uso números enteros y largos para ayudar a la legibilidad de mi código , particularmente en los bucles, donde un entero indica que se espera que el bucle sea pequeño (menos de 1000 iteraciones), mientras que un Long me dice que se espera que el bucle sea bastante grande (más de 1000).
Tenga en cuenta que este umbral subjetivo está muy por debajo del límite superior de Integer, uso Longs solo para hacer la distinción entre mis propias definiciones de pequeño y grande.
Como se señaló en otras respuestas, la diferencia real entre int y long es el tamaño de su espacio de memoria y, por lo tanto, el tamaño del número que puede contener.
Aquí está la documentación completa sobre estos tipos de datos http://msdn.microsoft.com/en-us/library/office/ms474284(v=office.14).aspx
un número entero es de 16 bits y puede representar un valor entre -32,768 y 32,767
un largo es de 32 bits y puede representar de -2,147,483,648 a 2,147,483,647
y hay un LongLong que es de 64 bits y puede manejar como 9 pentilion
Una de las cosas más importantes para recordar sobre esto es que los tipos de datos difieren tanto por idioma como por sistema operativo / plataforma. En su mundo de VBA, un largo es de 32 bits, pero en c # en un procesador de 64 bits, un largo es de 64 bits. Esto puede introducir una confusión significativa.
Aunque VBA no lo admite, cuando se muda a cualquier otro idioma en .net o java u otro, prefiero usar los tipos de datos del sistema de int16 , int32 e int64, lo que me permite ser mucho más transparente sobre los valores que se puede mantener en estos tipos de datos.
Este es un problema de espacio versus necesidad .
En algunas situaciones es necesario usar un largo. Si está recorriendo filas en un archivo de Excel grande, la variable que contiene el número de fila debe ser larga.
Sin embargo, a veces sabrá que un número entero puede manejar su problema y usar un largo sería una pérdida de espacio (memoria). Las variables individuales realmente no hacen mucha diferencia, pero cuando comienzas a tratar con matrices, puede hacer una gran diferencia.
-
En VBA7, los enteros son 2 bytes y los largos son 4 bytes
-
Si tiene una matriz de 1 millón de números entre 1 y 10, el uso de una matriz Integer requeriría aproximadamente 2 MB de RAM, en comparación con aproximadamente 4 MB de RAM para una matriz larga.
Tomé el método de @ PGSystemTester y lo actualicé para eliminar alguna variabilidad potencial. Al colocar el bucle en las rutinas, esto elimina el tiempo necesario para llamar a la rutina (que es mucho tiempo). También he desactivado la actualización de pantalla para eliminar cualquier retraso que esto pueda causar.
Long
aún obtuvo el mejor rendimiento, y dado que estos resultados se limitan más estrechamente a los impactos de los tipos de variables solos, vale la pena señalar la magnitud de la variación.
Mis resultados (escritorio, Windows 7, Excel 2010):
Código usado:
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
VBA tiene mucho equipaje histórico.
Un número
Integer
tiene 16 bits de ancho y era un buen tipo numérico predeterminado cuando la arquitectura de 16 bits / tamaños de palabra prevalecían.
Un
Long
tiene 32 bits de ancho y (IMO) debe usarse siempre que sea posible.