vba でOverflow
エラーに関連する質問をよく見ます。
私の質問は、すべての数値変数(integer
などを除く)を単にdouble
として定義するのではなく、long
変数宣言を使用する理由です。
値が32,767の制限を超えないことを保証できるforループのような操作を実行している場合を除き、パフォーマンスまたはlong
を使用しないことを指示する何かに影響がありますか?
整数変数は16ビット(2バイト)の数値として保存されます
ロング(ロング整数)変数は、符号付き32ビット(4バイト)番号として保存されます
そのため、メモリスペースの削減という利点があります。 Integerは、longの半分のメモリを占有します。ここで、2バイトについて説明しているので、整数のTONを保存しない限り、実際の違いは生じません。
BUTon32ビットシステムでは、16ビット整数は、動作する数値の範囲が広くなることなく、暗黙的にlongに変換されます。オーバーフローは依然として発生し、同じ量のメモリを消費します。 パフォーマンスはhurt になる場合もあります。これは、データ型を変換する必要があるためです(非常に低いレベルで)。
私が探していたリファレンスではなく、....
私の理解では、基になるVBエンジンは、整数として宣言されていても整数をlongに変換します。したがって、わずかな速度低下が見られます。私はこれをしばらく信じており、おそらくそれが上記の声明が出された理由でもあると思いますが、私は推論を求めませんでした。
これは私が探していたリファレンスです。
簡単な答え、32ビットシステムでは、2バイト整数は4バイト長整数に変換されます。実際に他の方法はないので、それぞれのビットはあらゆる形式の処理に対して正しく整列します。以下を考慮してください
MsgBox Hex(-1) = Hex(65535) ' = True
明らかに-1は65535に等しくありませんが、コンピューターは正しい答え、つまり "FFFF" = "FFFF"を返しています。
ただし、-1を長い最初に強制した場合、正しい答えが得られます(32535より大きい65535は自動的に長いです)
MsgBox Hex(-1&) = Hex(65535) ' = False
"FFFFFFFF" = "FFFF"
一般に、VBAには、おそらく整数を受け取ることを期待するいくつかのレガシーAPIを除いて、現代のシステムで「整数として」を宣言する意味がありません。
そしてついに、私は msdn documentation を本当に見つけました。
従来、VBAプログラマは、必要なメモリが少ないため、整数を使用して小さな数値を保持していました。ただし、最近のバージョンでは、VBAは整数型として宣言されている場合でも、すべての整数値をLong型に変換します。そのため、整数変数を使用することによるパフォーマンス上の利点はなくなりました。実際、VBAは変数を変換する必要がないため、Long変数はわずかに高速になる場合があります。
したがって、要約すると、最近Integer
タイプを使用する正当な理由はほとんどありません。 Unless16ビット整数を期待する古いAPI呼び出しと相互運用する必要がある場合を除きます。
指摘する価値のあることの1つは、一部の古いAPI関数は16ビット(2バイト)整数のパラメーターを期待している可能性があり、32ビットであり、整数(すでに4バイトの長さ)を渡そうとしている場合参照により、バイト長の違いにより機能しません。
それを指摘してくれたVba4Allに感謝します。
他の回答で述べたように、intとlongの本当の違いは、メモリスペースのサイズであり、したがって、保持できる数値のサイズです。
これらのデータ型に関する完全なドキュメントを次に示します http://msdn.Microsoft.com/en-us/library/office/ms474284(v = office.14).aspx
Integerは16ビットで、-32,768〜32,767の値を表すことができます
Longは32ビットで、-2,147,483,648から2,147,483,647を表すことができます
LongLongがあります。これは64ビットで、9ペンティリオンのように処理できます
これについて覚えておくべき最も重要なことの1つは、データ型が言語とオペレーティングシステム/プラットフォームの両方によって異なることです。 VBAの世界ではlongは32ビットですが、64ビットプロセッサのc#ではlongは64ビットです。これは大きな混乱を招く可能性があります。
VBAはそれをサポートしていませんが、.netまたはJavaまたはその他の言語に移行するときは、int16、int32およびint64これらのデータ型に保持できる値について、より透明性を高める必要があります。
VBAには多くの歴史的な荷物があります。
Integer
は16ビット幅であり、16ビットアーキテクチャ/ワードサイズが普及しているときは、デフォルトの数値型として適切でした。
Long
は32ビット幅であり、可能な限り(IMO)を使用する必要があります。
この投稿は4年ですが、私はこれに興味があり、いくつかのテストを実行しました。注意すべき最も重要なことは、コーダーがALOMESが変数をSOMETHINGとして宣言する必要があることです。宣言されていない変数は明らかに最悪の結果を出しました(宣言されていない変数は技術的にはVariant
です)
Long
は最も高速に動作したため、Long
の代わりにInteger
を常に使用するというMicrosoftの推奨事項が理にかなっていると考えなければなりません。 Byte
でもtrueと同じように推測しますが、ほとんどのコーダーはこれを使用しません。
64ビットWindows 10ラップトップの結果
使用コード:
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
これはスペース vs 必要性の問題です。
状況によっては、ロングを使用するのは必要性です。大きなExcelファイルで行をループしている場合、行番号を保持する変数は長いはずです。
ただし、整数で問題を処理でき、longを使用するとスペース(メモリ)が無駄になることがわかっている場合があります。個々の変数が実際に大きな違いを生むことはありませんが、配列の取り扱いを開始すると、大きな違いを生むことができます。
VBA7では、整数は2バイトで、長整数は4バイトです
整数配列を使用すると、1〜10の100万個の配列がある場合、約4MBの_と比較して、2MBのRAMを使用しますaboutRAM長い配列の場合。
@PGSystemTesterのメソッドを使用して更新し、潜在的な変動を削除しました。ルーチンにループを配置することにより、ルーチンを呼び出すのにかかる時間(多くの時間)が削除されます。また、これにより発生する可能性のある遅延を削除するために、画面の更新をオフにしました。
Long
は依然として最高のパフォーマンスを発揮し、これらの結果は変数タイプのみの影響により限定されているため、変動の大きさは注目に値します。
私の結果(デスクトップ、Windows 7、Excel 2010):
使用されるコード:
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
既に述べたように、LongmayはIntegerの2倍のスペースを取ります。他の人が既に言及したように、現在のコンピューターの大容量は、余分な余分な大量のデータを処理している場合を除いて、パフォーマンスにまったく違いがないを意味します:
100万個の値を考慮すると、整数とLongの使用の違いは各値で2バイトになるため、2 * 1 000 000/1,024/1024 = 2 MB未満RAMの違い。これは、おそらくRAM容量の1%または0.1%よりもはるかに小さいです。
PGSystemTesterによって行われたベンチマークを考慮すると、それぞれ4つの操作の100億バッチを処理するときに、ロングと整数の間に811-745 = 66秒の差があることがわかります。数を100万回の操作に減らすと、66/10 000/4 = = 実行時間の差が2ms未満になります。
私は個人的に整数とロングを使用してコードの可読性を高める、特にループでは、整数がループが小さい(1000回未満の繰り返し)と予想されることを示しますが、ロングはループがかなり大きい(1000以上)と予想されます。
この主観的なしきい値はIntegerの上限をはるかに下回ることに注意してください。Longsは、自分自身の大小の定義を区別するためだけに使用します。