えくせるちゅんちゅん

ことりがエクセルをちゅんちゅんするブログ

VBAで最速の整数型を調べてみた

今回は64bit版VBAの整数型で使えるIntergerとLongとLongLongのうち、どれが最速なのかを調べてみました。

f:id:Kotori-ChunChun:20190727173207p:plain


きっかけ

先日Twitterにて、VBAの変数の型はIntegerかLongかどちらにすべきだろうかという話が上がりました。

https://twitter.com/shota_Excellent/status/1151817485882019840?s=20

既に先人の方々が調査を済ませており、LongはIntegerの70%~90%の処理時間であることが証明されています。

なお、Microsoftも公式ホームページにてInteger型変数にパフォーマンス上の利点は無いと示しています。

(詳細は「参考資料」のリンクを御覧ください。)

で、解決済みの案件に一太刀入れたくなるのが、私。

Excel 2019からは64bit版が推奨になったけど、今でもLong型最速説が通用するのだろうか。

実はLongLong型のほうが高速になるんじゃないか。と、考えずにはいられない訳でして。

思い立ったが吉日。試してみました。


仕様

今回検証するかもしれない型はこちら。

データ型 表記 消費メモリ 最低値 最大値 型文字 利用条件
バイト型 Byte 1バイト 0 255 - -
整数型 Integer 2バイト -32,768 32,767 % -
長整数型 Long 4バイト -2,147,483,648 2,147,483,647 & -
長長整数型 LongLong 8バイト -9,223,372,036,854,775,808 9,223,372,036,854,775,807 ^ 64bit限定
システム依存の長整数型 LongPtr 4バイト または 8バイト -2147483648 または -9,223,372,036,854,775,808 2147483647 または 9,223,372,036,854,775,807 - 2010以降限定
なんか Variant 16バイト ~ 22バイト なんでも なんでも - -

LongPtr データ型

LongLong データ型

ところで、LongLong型は64bit版のOfficeでしかコンパイルできないという問題があります。

したがって、ちゃんと32ビット版のOfficeでもコンパイルできるLongPtrのほうが、実用性としては高いような気がします。

気になるのはLongPtrが32bitにおけるLong、64bitにおけるLongLongと同じ結果になるかどうか。ですね。


メモリ消費量の確認

速度の比較に入る前に・・・消費メモリを確認しておきましょう。


以下の結果から、メモリの消費量は仕様に記載されているバイト数と比例することが確認できました。

(Variantは若干の疑問が残りますが)

LongPtrのメモリ消費量も、仕様と同じでビット数に合わせて妥当な方を選択しているということが確認できました。


VBA

'メモリ消費量の確認
Option Explicit

Const MAX = 10 ^ 4

Sub メモリ使用量Integer()
    Dim arr(1 To MAX, 1 To MAX) As Integer
    Stop
End Sub

Sub メモリ使用量Long()
    Dim arr(1 To MAX, 1 To MAX) As Long
    Stop
End Sub

Sub メモリ使用量LongPtr()
    Dim arr(1 To MAX, 1 To MAX) As LongPtr
    Stop
End Sub

#If Win64 Then
Sub メモリ使用量LongLong()
    Dim arr(1 To MAX, 1 To MAX) As LongLong
    Stop
End Sub
#End If

Sub メモリ使用量Variant()
    Dim arr(1 To MAX, 1 To MAX) As Variant
    Stop
End Sub


結果(32bit)

タスクマネージャーの「詳細」タブにて、EXCEL.EXEの「メモリ(アクティブな以下略)」を使って、マクロの実行前とSTOP中の差分を算出しました。

Dim arr(1 To 10000) As Type 実使用メモリKB 仕様上消費メモリ 1バイト当たり
Byte 98,224 1 98,224
Integer 195,528 2 97,764
Long 390,536 4 97,634
LongPtr 390,908 4 97,727
Variant 1,562,656 16 97,666


結果(64bit)

Dim arr(1 To 10000) As Type 実使用メモリKB 仕様上消費メモリ 1バイト当たり
Byte 97,664 1 97,664
Integer 195,432 2 97,716
Long 390,628 4 97,657
LongLong 781,252 8 97,657
LongPtr 781,252 8 97,657
Variant 2,252,052 22 102,366

Variantは整数時16と仕様に記載があるが、本件では22バイト消費した。(が、1バイト換算が変な数字になるのが疑問)


比較1

Forループのカウンタに割り当ててみました。


VBA

Sub t1()
    tStart = Timer
    
'    Dim i   As Byte, j As Byte 'ERR
'    Dim i   As Integer, j As Integer
    Dim i   As Long, j As Long
'    Dim i   As LongPtr, j As LongPtr
'    Dim i   As LongLong, j As LongLong
'    Dim i    As Variant, j As Variant
    For i = 1 To 32766
        For j = 1 To 32766
        Next
    Next
    
    Debug.Print Format$(Timer - tStart, "0.00") & " sec."
End Sub


結果(32bit)

所要時間(秒) 最速を100%とした時
Integer 3.21 100%
Long 3.30 103%
LongPtr 3.29 102%
Variant 4.74 148%

おや、これは・・・?IntegerのほうがLongより速いという結果になってしまいました。※Core i7

追記:何度やってもIntegerのほうが微妙に早かったのですが、別のPCでも試したところ同一の結果で安定しました。※Xeon E5


結果(64bit)

所要時間(秒) 最速を100%とした時
Integer 6.08 167%
Long 4.88 134%
LongPtr 3.67 101%
LongLong 3.63 100%
Variant 4.58 126%

64bitでは、LongLong > Long > Integerという結果になりました。

※32bitと64bitを計測したPCは性能が異なります。2つの表の時間を比較することは無意味です。


比較2

今度はカウンタはLongに固定して、たんなるインクリメントを繰り返した例で試してみます。


VBA

Sub t2()

    Dim cnt   As Integer
'    Dim cnt   As Long
'    Dim cnt   As Single
'    Dim cnt   As Double
'    Dim cnt   As Currency
'    Dim cnt   As LongLong
'    Dim cnt   As LongPtr
'    Dim cnt   As Variant
    
    tStart = Timer
    
    Dim i As Long, j As Long
    For i = 1 To 10 ^ 5
        cnt = 0
        For j = 1 To 10000
            cnt = cnt + 1
        Next
    Next
    
    Debug.Print Format$(Timer - tStart, "0.00") '& " sec."
    
End Sub


結果(32bit)

所要時間(秒) 最速を100%とした時
Integer 7.76 127%
Long 7.38 121%
LongPtr 6.09 100%
Variant 14.37 236%


結果(64bit)

所要時間(秒) 最速を100%とした時
Integer 8.75 125%
Long 8.63 123%
LongPtr 7.14 102%
LongLong 7.02 100%
Variant 13.78 196%

※32bitと64bitを計測したPCは性能が異なります。2つの表の時間を比較することは無意味です。


使い分けが必要な場面


Integer

  • 16bitの値を返すAPIからデータを受け取る場合
  • メモリを少しでも削減したい時
  • 最大値が32767なことを利用して実行時エラーを起こしたい時
    • xls形式の行数
    • xlsx形式の列数


Long

  • 32bitの値を返すAPIからデータを受け取る場合
  • 最も互換性と汎用性が高い
  • xlsx形式における最大行数に対応する時


LongPtr

  • bit依存の値を返すAPIからデータを受け取る場合
  • 変数の容量が32bit・64bitどちらでも良い場合
  • メモリに余裕がある時は、少しでも巨大データを扱えるようにしたい時
  • Excel 2007以前では絶対に使わないマクロの場合


LongLong

  • 64bitの値を返すAPIからデータを受け取る場合
  • 明らかに巨大なデータを扱うことを予め予期している時
  • 64bit環境でしか使わないことを前提としている場合
  • #IF...Then...#ElseディレクティブでLongとLongLongを明示的に使い分ける場合


参考資料


公式

docs.microsoft.com - The Integer, Long, and Byte Data Types)

しかし、最近のバージョンでは、Integer型として宣言されていても、VBAはすべての整数値をLong型に変換します。したがって、Integer変数を使用することによるパフォーマンス上の利点はなくなりました。実際、Long変数はVBAで変換する必要がないため、少し速くなる可能性があります。


以下のサイトでは、LongはIntegerの90%程度の処理時間だったようです。

説明が優しいので初心者にオススメです。

もりさんのプログラミング手帳 - 【ExcelVBA】Integer型 VS Long型、速いのはどっち?


以下のサイトは、何故Longのほうが早くなるのか、日本語で非常にわかりやすく解説されています。

VBA性能向上委員会 - Integer型とLong型はどちらを使うべき?

32bitのCPUの場合、処理単位が32bit単位で行われます。

そのため、16bitのInteger型は、一度32bitに変換してから処理を行います。

このPC内部での変換により、32bit領域のLong型の方が、結果的に速くなったというわけです。


不思議なことにこちらの記事は2018/9/9に調査された結果にもかかわらず、Integer>=Longという結果になっています。

肝心の環境やバージョンを明記されていないので非常に気になります。

Excel作業をVBAで効率化 - VBAの数値型で一番速いのはどれか


まとめ

二種類の計測結果を見て分かるように、ちょっと別のコードが実行されたら埋もれてしまう程度の差しかありませんが、確かに64bit Office環境下ではLongLongを使ったほうが高速なようです。

どうしてもパフォーマンスを優先したい場合は

  • メモリに余裕がある
  • Office 2007以前は動作対象に含めない
  • この変数はLongでもLongLongでもどっちでも良い

という条件の元、LongPtrにしても良さそうです。

無闇矢鱈にLongPtrにすると、思わぬところでトラブルがおこるかもしれませんし、環境によって仕様が変わることになります。

既存のプログラムは、特別な理由がない限りはLongから変えないほうが良いのではないでしょうか。

私は「ここぞ」という時にだけLongPtrを使って行こうと思います。

以上


何か御座いましたらコメント欄、またはTwitterからどうぞ♪

それではまた来週♪ ちゅんちゅん(・8・)

プライバシーポリシー