Зачем использовать Integer вместо Long?
Я часто вижу вопросы, связанные с ошибками Overflow
с vba.
Мой вопрос, почему использовать integer
переменную декларацию вместо того, чтобы просто определить все числовые переменные ( за исключением double
и т.д.), как long
?
Если вы не выполняете операцию, подобную циклу for, где вы можете гарантировать, что значение не превысит ограничение 32 767, это повлияет на производительность или что-то еще, что будет диктовать отсутствие использования long
?
Ответы
Ответ 1
Целочисленные переменные хранятся как 16-битные (2-байтовые) числа
MSDN
Длинные (длинные целые) переменные хранятся как 32-битные (4-байтовые) числа со знаком
MSDN
Таким образом, выгода заключается в уменьшении объема памяти. Integer занимает половину памяти, которую занимает long. Теперь мы говорим о 2 байтах, так что это не будет иметь большого значения, если вы не храните TON целых чисел.
НО в 32- разрядной системе 16-разрядное целое число тихо преобразуется в длинное без использования большего диапазона чисел для работы. Переполнения по-прежнему случаются и занимают столько же памяти. Производительность может даже ухудшиться, потому что тип данных должен быть преобразован (на очень низком уровне).
Не ссылка, которую я искал, но....
Насколько я понимаю, основной движок VB преобразует целые числа в длинные, даже если он объявлен как целое число. Поэтому можно отметить небольшое снижение скорости. Я верил этому в течение некоторого времени, и, возможно, именно поэтому было сделано вышеупомянутое выражение, я не просил аргументации.
озгрид форумы
Это ссылка, которую я искал.
Короткий ответ: в 32-разрядных системах 2-байтовые целые числа преобразуются в 4-байтовые значения. На самом деле другого пути нет, поэтому соответствующие биты правильно выстраиваются для любой формы обработки. Рассмотрим следующее
MsgBox Hex(-1) = Hex(65535) ' = True
Очевидно, что -1 не равен 65535, но компьютер возвращает правильный ответ, а именно: "FFFF" = "FFFF"
Однако, если бы мы принудили -1 к длинному первому, мы получили бы правильный ответ (65535, превышающий 32 КБ, автоматически является длинным)
MsgBox Hex(-1&) = Hex(65535) ' = False
"FFFFFFFF" = "FFFF"
Как правило, в VBA нет смысла объявлять "как целое число" в современных системах, за исключением, возможно, некоторого устаревшего API, который ожидает получить целое число.
форум pcreview
И наконец я нашел документацию MSDN, которую я действительно искал.
Традиционно, программисты VBA использовали целые числа для хранения небольших чисел, потому что им требовалось меньше памяти. Однако в последних версиях VBA преобразует все целочисленные значения в тип Long, даже если они объявлены как тип Integer. Таким образом, больше нет преимущества в производительности при использовании целочисленных переменных; на самом деле, длинные переменные могут быть немного быстрее, потому что VBA не нужно преобразовывать их.
Итак, в итоге, почти нет веских оснований для использования Integer
типа в наши дни. Если вам не нужно взаимодействовать со старым вызовом API, который ожидает 16-битное int.
Стоит отметить, что некоторые старые функции API могут ожидать параметры, которые являются 16-разрядными (2-байтовыми) целыми числами, и если вы используете 32-разрядный код и пытаетесь передать целое число (это уже 4-байтовый код) по ссылке он не будет работать из-за разницы в длине байтов.
Спасибо Vba4All за указание на это.
Ответ 2
Как отмечалось в других ответах, реальная разница между int и long - это размер его памяти и, следовательно, размер числа, которое он может содержать.
вот полная документация по этим типам данных: http://msdn.microsoft.com/en-us/library/office/ms474284(v=office.14).aspx
целое число составляет 16 бит и может представлять значение между -32, 768 и 32,767
Длинный составляет 32 бита и может представлять -2, чтобы 2,147,483,647 147483648
и есть LongLong, который составляет 64 бита и может обрабатывать как 9 Pentilion
Важно помнить, что типы данных различаются в зависимости от языка и операционной системы/платформы. В вашем мире VBA long - 32 бита, но в С# на 64-битном процессоре long - 64 бита. Это может привести к значительной путанице.
Хотя VBA не поддерживает его, при переходе на любой другой язык в .net, java или других, я очень предпочитаю использовать системные типы данных int16, int32 и int64, что позволяет мне гораздо более прозрачно понимать значения, которые могут быть проведены в этих типах данных.
Ответ 3
У VBA много исторического багажа.
An Integer
имеет ширину 16 бит и является хорошим цифровым типом по умолчанию, когда были распространены 16-битные архитектуры/размеры слов.
A Long
имеет ширину 32 бита и (IMO) следует использовать там, где это возможно.
Ответ 4
Несмотря на то, что этому сообщению четыре года, мне было интересно об этом и провела несколько тестов. Самое главное отметить, что кодер должен ВСЕГДА объявить переменную как ЧТО-ТО. Необъявленные переменные явно выполняли худшие (необъявленные технически Variant
)
Long
работал быстрее, поэтому я должен думать, что рекомендация Microsoft всегда использовать Long
вместо Integer
имеет смысл. Я предполагаю то же самое, что и у Byte
, но большинство кодеров не используют это.
РЕЗУЛЬТАТЫ НА ОКОНЧАТЕЛЬСТВЕ 64 БИТ WINDOWS 10
![Variable Olympics]()
Используемый код:
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
Ответ 5
Это проблема space vs необходимость.
В некоторых ситуациях требуется необходимость использовать длинный. Если вы перебираете строки в большом файле excel, переменная, содержащая номер строки, должна быть длинной.
Однако иногда вы узнаете, что целое число может справиться с вашей проблемой, и использование длинной будет пустой тратой пространства (память). Отдельные переменные действительно не имеют большого значения, но когда вы начинаете разбираться с массивами, это может иметь большое значение.
-
В VBA7 целые числа составляют 2 байта, а longs - 4 байта.
-
Если у вас есть массив из 1 миллиона номеров между 1 и 10, использование массива Integer займет около 2 МБ ОЗУ, по сравнению с примерно 4 МБ ОЗУ для длинного массива.
Ответ 6
Я взял метод @PGSystemTester и обновил его, чтобы удалить потенциальную изменчивость. Помещая цикл в подпрограммы, это удаляет время, затрачиваемое на вызов подпрограммы (а это много времени). Я также отключил обновление экрана, чтобы устранить любые задержки, которые это может вызвать.
Long
все еще работали лучше всего, и поскольку эти результаты более тесно ограничены воздействием только типов переменных, стоит отметить величину вариаций.
Мои результаты (рабочий стол, Windows 7, Excel 2010):
![enter image description here]()
Используемый код:
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
Ответ 7
Как уже упоминалось, Long может занимать вдвое больше места, чем Integer. Как уже упоминали другие, высокая производительность современных компьютеров означает, что вы не увидите никакой разницы в производительности, если только вы не имеете дело с очень большими, очень большими данными:
памятиУчитывая 1 миллион значений, разница между использованием целых и длинных будет составлять 2 байта для каждого значения, так что разница в 2 * 1 000 000/1024/1024 = меньше 2 МБ Ваша RAM, которая, вероятно, намного меньше, чем 1% или даже 0,1% от вашей оперативной памяти.
Обработка
Учитывая эталонный тест PGSystemTester, вы можете увидеть разницу в 811 - 745 = 66 секунд между Long и Integer при обработке 10 миллиардов пакетов по 4 операции в каждой. Уменьшите число операций до 1 миллиона операций, и мы можем ожидать, что разница во времени выполнения составит 66/10 000/4 = менее 2 мс.
Я лично использую Integer и Longs, чтобы улучшить читаемость моего кода, особенно в циклах, где Integer указывает, что цикл, как ожидается, будет небольшим (менее 1000 итераций), тогда как Long сообщает, что цикл ожидается быть довольно большим (более 1000).
Обратите внимание, что этот субъективный порог намного ниже верхнего предела Integer, я использую Longs просто для того, чтобы провести различие между моими собственными определениями малого и большого.
Ответ 8
Возможно, CS grad может объяснить это лучше, но да целому числу требуется меньше памяти для хранения (может быть, не очень важно в очень простом VBA script).
Он также гарантирует/подтверждает, что переменная всегда будет целочисленной (не десятичной). Я уверен, что если вы сохраните 6.7 как целое число, оно будет преобразовано в число 7 в VBA.
Возможно, это не лучшая практика, но могут быть случаи, когда это необходимо. Я считаю, что главная цель - проверка достоверности данных. В частности, да, для циклов, где что-то должно произойти Х количество раз - десятичное значение не имеет смысла.
Первичное различие - память, хотя - если я помню длинный бит 64 бит, а целое - 32 бит.