なぜLongではなくIntegerを使うのか

vba integer long-integer integer-overflow


vbaでの Overflow エラーに関する質問がよくあります。

使用する理由私の質問は integer だけですべての数値変数を定義するのではなく、変数の宣言を(除く double などなど) long

forループのように、値が32,767の制限を超えないことを保証できる操作を実行している場合を除いて、パフォーマンスなどに影響を及ぼして long を使用しないことはできますか?




Answer 1 RubberDuck


整数変数は16ビット(2バイト)の数値として格納されます。

Office VBAリファレンス

長い(長い整数)変数は、符号付き 32 ビット(4 バイト)の数値として格納されます。

Office VBAリファレンス

つまり、その利点はメモリ容量の削減にあります。整数はLongの半分のメモリを占有します。今は2バイトの話をしているので、個々の整数には大きな違いはありませんが、大量の整数(大規模な配列など)を扱う場合には、メモリ使用量が非常に重要になるので注意が必要です。

しかし 32ビットシステムでは、メモリ使用量が半分になり、パフォーマンスが低下します。プロセッサが実際に16ビット整数を使用して何らかの計算(ループカウンターのインクリメントなど)を実行すると、処理する数値の範囲が大きくなることなく、値が暗黙的に一時的なLongに変換されます。オーバーフローは引き続き発生し、プロセッサが計算の値を格納するために使用するレジスタは、どちらの方法でも同じ量のメモリ(32ビット)を使用します。パフォーマンスがさえすることができる傷つけるデータ型が(非常に低いレベルで)に変換する必要があるため。

探していた参考にはなりませんでしたが......。

私の理解では、基礎となるVBエンジンは、整数として宣言されている場合でも、整数をlongに変換します。したがって、わずかな速度低下を指摘することができます。私はいくつかの時間のためにこれを信じていたし、おそらくそれはまた、上記のステートメントが行われた理由も、私は理由を求めていませんでした。

オズグリッドフォーラム

私が探していた参考になりました。

簡単な答えは、32ビットシステムでは、2バイトの整数は4バイトのLongsに変換されます。それぞれのビットが処理のどのような形式でも正しく並ぶように、実際には他の方法はありません。次のように考えてみてください。

MsgBox Hex(-1) = Hex(65535) ' = True

明らかに-1は65535と等しくありませんが、コンピュータは正しい答えを返しています、すなわち、"FFFFF"="FFFF"

しかし、我々は最初に長いに-1を強制していた我々は正しい答えを得ていただろう(32kよりも大きい65535は自動的に長いです)。

MsgBox Hex(-1&) = Hex(65535) ' = False

"ffffffffff"="ffffff"

一般的に、最近のシステムではVBAで "As Integer "を宣言する必要はありませんが、おそらく整数を受け取ることを期待するいくつかのレガシーAPIを除いては、です。

pcreviewフォーラム

そしてようやく、本当に探していたmsdnのドキュメントを見つけました。

伝統的に,VBAのプログラマは,少ないメモリを必要とするため,小さな数値を保持するために整数型を使用してきました.しかし、最近のバージョンでは、VBAは、整数型として宣言されていても、すべての整数値をLong型に変換します。そのため、整数型変数を使うことによるパフォーマンスの優位性はもはやありません;実際、VBAが変換する必要がないので、Long変数の方がわずかに速くなるかもしれません。

コメントに基づいて明確にする:整数はまだ店に少ないメモリを必要とする-整数の大規模な配列は、同じ寸法の長い配列よりも大幅に少ないRAMが必要になります。ただし、プロセッサは32ビットのメモリチャンクで動作する必要があるため、VBA は計算を実行するときに一時的に整数をLongに変換します。


したがって、要約すると、最近は Integer 型を使用する正当な理由はほとんどありません。ない限り、あなたは16ビットのintを期待古いAPI呼び出しで相互運用する必要がある、またはあなたが小さな整数とメモリの大規模な配列を使用して作業している貴重です。

ひとつ指摘しておきたいのは、古いAPI関数の中には16ビット(2バイト)の整数のパラメータを期待しているものがあり、32ビット版の場合、(すでに4バイト長の)整数を参照して渡そうとすると、バイト長の違いにより動作しないということです。

Vba4Allさん、ご指摘ありがとうございます。




Answer 2 Patrick


他の回答にも書いてありますが、intとlongの本当の違いは、そのメモリ空間の大きさであり、したがって、それが保持できる数の大きさです。

これらはこれらのデータ型の完全なドキュメントです http://msdn.microsoft.com/en-us/library/office/ms474284(v=office.14).aspx

整数 16ビットであり、-32,768と32,767の間の値を表すことができます

ロング 32ビットで2,147,483,647に-2147483648を表すことができ

とがあるLONGLONG 64ビットであり、9 pentilionのように扱うことができます

これについて覚えておくべき最も重要なことの1つは、データ型は言語とオペレーティングシステム/プラットフォームの両方によって異なるということです。VBAの世界ではlongは32ビットですが、64ビットプロセッサ上のc#ではlongは64ビットです。これは重大な混乱を引き起こす可能性があります。

VBAはそれをサポートしていませんが、.netやjavaなどで他の言語に移動するときは、int16int32、およびint64のシステムデータ型を使用することをお勧めします。これらのデータ型で保持できます。




Answer 3 Alex K.


VBAは歴史的な荷物が多い。

アン Integer 16ビット幅で、16ビットアーキテクチャ/ワードサイズが流行した適切なデフォルト数値型のバックでした。

A Long 32ビット幅と(IMO)が可能な限り使用すべきです。




Answer 4 PGSystemTester


この投稿は4歳ですが、私はこれに興味があり、いくつかのテストを実行しました。注意すべき最も重要なことは、コーダーは常に変数をSOMETHINGとして宣言する必要があるということです。宣言されていない変数は明らかに最悪のパフォーマンスを示しました(宣言されていない変数は技術的には Variant

Long が最も高速に実行されたため、常に Integer の代わりに Long を使用するというMicrosoftの推奨事項は理にかなっていると考えなければなりません。私は 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



Answer 5 Alter


これはスペース必要性の問題です。

状況によっては、longを使用する必要があります。大規模なExcelファイルで行をループしている場合、行番号を保持する変数は長いはずです。

ただし、整数で問題を処理できることや、longを使用するとスペース(メモリ)が浪費されることがわかる場合があります。個々の変数は実際には大きな違いはありませんが、配列の処理を開始すると、大きな違いが生じる可能性があります。

  • VBA7では,整数は2バイト,longは4バイトです.

  • 1〜10の間に100万個の数値の配列がある場合、Integer配列を使用すると 2MBのRAMを消費しますが、長い配列では約4MBのRAMを使用します。