¿Por qué utilizar números enteros en lugar de largos?

Resuelto Gareth asked hace 10 años • 9 respuestas

A menudo veo preguntas relacionadas con Overflowerrores convba.

Mi pregunta es ¿por qué utilizar la integerdeclaración de variables en lugar de simplemente definir todas las variables numéricas (excluyendo, doubleetc.) 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?

Gareth avatar Oct 16 '14 23:10 Gareth
Aceptado

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 Integertipo 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.

RubberDuck avatar Oct 16 '2014 16:10 RubberDuck

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)

Longfuncionó más rápido, así que tengo que pensar que la recomendación de Microsoft de usar siempre Longen lugar de Integertiene 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

Olimpiadas variables

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
pgSystemTester avatar Aug 04 '2018 19:08 pgSystemTester