型によって速度に違いがある
プログラミング言語でたまに話題になるのが「数値型はこの型が一番速いのでこれを使いましょう」という話です。VBAについても同じように型によって処理速度に違いが出ます。
そこで数値型のInteger型、Long型、Single型、Double型、Currency型、LongLong型(64bit版のみ)の6つを比較してみます。Byte型やBoolean型も数値型ではありますが、用途が違うので除外します。
32bit環境(2010年度仕様程度:Windows7 + Core i3 + Office2010)と64bit環境(2020年度仕様程度:Windows10 + Ryzen9 3900X + Office365)のそれぞれで計測しました。
先に答えを書いてしまうと、環境によって速い順が異なりました。32bit環境(Windows7 + Core i3 +Office2010)では速かった順でInteger、Long、Currency、Double、Singleでした。64bit環境(Windows10 + Ryzen9 3900X+Office365)ではDouble、Single、Long、Integer、LongLong、Currencyでした。
ただ、いずれの場合も速度の違いは微々たるものでした。64bit環境に至ってはほとんど差がありませんでした。
比較用コード
以下のコードで処理の開始と終了をマイクロ秒で取得して、開始と終了の差から処理時間を計測します。
処理自体は100000回×10000回、つまり10億回のループで足し算を行うプログラムです。
実行する際に2行目から6行目で計測対象の数値型のみコメントをはずして実行します。
比較には「VBAでミリ秒やマイクロ秒の計測を行う」で紹介しているマイクロ秒計測関数「GetMicroSecond」を利用しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
Sub CompareDataType() Dim i As Integer ' Dim i As Long ' Dim i As Single ' Dim i As Double ' Dim i As Currency ' Dim i As LongLong Dim id1 Dim id2 Dim microStart As Double Dim microEnd As Double Dim microDiff As Double microStart = GetMicroSecond For id1 = 1 To 100000 i = 0 For id2 = 1 To 10000 i = i + 1 Next Next microEnd = GetMicroSecond microDiff = microEnd - microStart Debug.Print microDiff End Sub |
比較結果
結果は以下の通り、環境によって変わりました。
32bit環境での結果
順位 | 数値型 | 平均速度 | 1位と速度差率 |
---|---|---|---|
1位 | Integer | 12.4480567194987 | 100.00% |
2位 | Long | 12.4500986955128 | 100.02% |
3位 | Currency | 15.1783854221925 | 121.93% |
4位 | Double | 18.5107456908387 | 148.70% |
5位 | Single | 18.7996578843275 | 151.02% |
32bit環境(Windows7 + Core i3 + Office2010)では、Integer、Long、Currency、Double、Single、の順に速かったです。
IntegerとLongは0.02%しか違いがなく、ほとんど速度差はありませんでした。
意外だったのはCurrency型が結構速かったことです。Currency型は15桁の整数と4桁の小数を保持できます。扱う数値が整数15桁+小数4桁のCurrency型の範囲に入ることが分かっている場合は、Double型よりもCurrency型を利用した方が処理速度向上が見込めます。
SingleとDoubleでは、一般的には単精度(Single)と倍精度(Double)では単精度(Single)の方が速いと言われます。VBAの実装は分からないのですが、言語やインタプリターやコンパイラーによっては単精度は一度倍精度に変換して単精度に戻すようなものもあるため、そういう場合は倍精度(Double)の方が速かったりします。なので、SingleとDoubleでDoubleが速かったのは私の環境だけかも、という点を補足しておきます。
64bit環境での結果
順位 | 数値型 | 平均速度 | 1位と速度差率 |
---|---|---|---|
1位 | Double | 6.53384666005150 | 100.00% |
2位 | Single | 6.62837783996947 | 101.45% |
3位 | Long | 6.68528776005842 | 102.32% |
4位 | Integer | 6.75233754003420 | 103.34% |
5位 | LongLong | 7.15234209997579 | 109.47% |
6位 | Currency | 7.18892749999650 | 110.03% |
64bitOS(Windows10 + Ryzen 9 3900X + Office365)では、Double、Single、Long、Interger、LongLong、Currency、の順に速かったです。
ただ、10億回で1位のDoubleの6.5秒と6位のCurrencyの7.18秒なので、数値型の速度を気にすること自体がほとんど意味をなさなくなっています。計測に使ったRyzen9 3900Xは12コア、24スレッドというかなり高速なCPUですが、それでも2020年以降のCPUは複数コア、複数スレッドが当たり前になりもう数値型での速度差がほとんど分からないぐらい高速になっているということです。
10億回のループでこの程度の差なので気にしなくてよい
上のテストコードは10億回ものループ処理を行っています。ここまでのループを行う処理は実際のVBAの処理ではなかなか無いと思います。VBAにそこまでの高速性を求めるようなことはほとんどないでしょう。
10億回で32bit環境が12秒から19秒の範囲、64bit環境が6.5秒から7.2秒の範囲ですから、差は微々たるものでしかありません。ここでは単純な足し算しかやっていませんが他の処理が増えれば一気に処理時間は増えることになります。
その上での差ですので、PCの処理速度がどんどん向上している現在では、もはや型での速度の違いを言ってもほとんど意味を成さなくなっているのが現実です。上の32bit環境ではそこそこの差がありますが、64bit環境は1位のDoubleと6位のCurrencyの差は、10億回演算しても1秒も差がありません。
IntegerとLongの比較で、「Long型の方が速い。なのでLong型一択で大丈夫。」みたいなことを書いてあるサイトが結構あるのですが、VBAのバージョンによって実装が違いあったり、PC環境や演算の仕方によって、上の結果の通り32bit環境ではInteger型が速いこともあれば、64bit環境ではLong型が速いこともあります。そしてこれが重要ですが、ほとんど差がありません。
確かにオーバーフローの予防を考えるのであればIntegerと比べればLongを使った方がいいと思いますが、それはあくまでもInteger型と比較すればという話であってLong型でもオーバーフローは発生しますし、Integer型で回避できなかったものがLong型だからといって必ず回避できるというわけでもありません。
そのため、Integer型やLong型の用途を無視して無条件に「Long型でOK」と言いきってしまうのはあまりにも速度偏重が強く、個人的には好みません。
むしろ、型の違いによる速度低下を気にするよりも、コーディングルールを適切に守りコードの品質を保つように努めた方がいいと思います。
比較結果詳細
細かいデータは特にいらないとは思いますが、上のコードを数値型ごとに5回ずつ実行した結果が以下になります。
そこまでばらつきも無い様子なので回数を増やしても変わらないと思い、5回ずつにしています。
32bit環境
数値型 | 回数 | 計測結果 | 平均 |
---|---|---|---|
Integer | 1回目 | 12.4729496697546 | 12.4480567194987 |
2回目 | 12.4415238746442 | ||
3回目 | 12.4542038372310 | ||
4回目 | 12.4340643484320 | ||
5回目 | 12.4375418674317 | ||
Long | 1回目 | 12.4478783314989 | 12.4500986955128 |
2回目 | 12.4387873804080 | ||
3回目 | 12.4419057826744 | ||
4回目 | 12.4624607504811 | ||
5回目 | 12.4594612325018 | ||
Single | 1回目 | 18.7943262018380 | 18.7996578843275 |
2回目 | 18.8006258363894 | ||
3回目 | 18.8132765399059 | ||
4回目 | 18.8008454335213 | ||
5回目 | 18.7892154099827 | ||
Double | 1回目 | 18.5085296386969 | 18.5107456908387 |
2回目 | 18.5132394270913 | ||
3回目 | 18.4997657733329 | ||
4回目 | 18.5088228454988 | ||
5回目 | 18.5233707695734 | ||
Currency | 1回目 | 15.1820697259391 | 15.1783854221925 |
2回目 | 15.1716516444285 | ||
3回目 | 15.1673936778679 | ||
4回目 | 15.1990255185228 | ||
5回目 | 15.1717865442042 |
64bit環境
数値型 | 回数 | 計測結果 | 平均 |
---|---|---|---|
Double | 1回目 | 6.59408730012365 | 6.53384666005150 |
2回目 | 6.56563029997051 | ||
3回目 | 6.51702979998663 | ||
4回目 | 6.49236790020950 | ||
5回目 | 6.50011799996719 | ||
Single | 1回目 | 6.49714199989103 | 6.62837783996947 |
2回目 | 6.66059960005805 | ||
3回目 | 6.66253690002486 | ||
4回目 | 6.66429349989630 | ||
5回目 | 6.65731719997711 | ||
Long | 1回目 | 6.74913280014880 | 6.68528776005842 |
2回目 | 6.69596919999458 | ||
3回目 | 6.66865999996662 | ||
4回目 | 6.65295680006966 | ||
5回目 | 6.65972000011243 | ||
Integer | 1回目 | 6.76376889995299 | 6.75233754003420 |
2回目 | 6.78791770013049 | ||
3回目 | 6.76623210008256 | ||
4回目 | 6.73979989998043 | ||
5回目 | 6.70396910002455 | ||
LongLong | 1回目 | 7.14884630008601 | 7.15234209997579 |
2回目 | 7.14873969997279 | ||
3回目 | 7.13808579999022 | ||
4回目 | 7.15316769992933 | ||
5回目 | 7.17287099990062 | ||
Currency | 1回目 | 7.13816550001502 | 7.18892749999650 |
2回目 | 7.20302979997359 | ||
3回目 | 7.19893419998698 | ||
4回目 | 7.20264680008404 | ||
5回目 | 7.20186119992286 |