web-dev-qa-db-ja.com

長いのではなく整数を使用する理由

vbaOverflowエラーに関連する質問をよく見ます。

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

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

57
Gareth

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

msdn

ロング(ロング整数)変数は、符号付き32ビット(4バイト)番号として保存されます

msdn

そのため、メモリスペースの削減という利点があります。 Integerは、longの半分のメモリを占有します。ここで、2バイトについて説明しているので、整数のTONを保存しない限り、実際の違いは生じません。

BUTon32ビットシステムでは、16ビット整数は、動作する数値の範囲が広くなることなく、暗黙的にlongに変換されます。オーバーフローは依然として発生し、同じ量のメモリを消費します。 パフォーマンスはhurt になる場合もあります。これは、データ型を変換する必要があるためです(非常に低いレベルで)。

私が探していたリファレンスではなく、....

私の理解では、基になるVBエンジンは、整数として宣言されていても整数をlongに変換します。したがって、わずかな速度低下が見られます。私はこれをしばらく信じており、おそらくそれが上記の声明が出された理由でもあると思いますが、私は推論を求めませんでした。

ozgrid forums

これは私が探していたリファレンスです。

簡単な答え、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を除いて、現代のシステムで「整数として」を宣言する意味がありません。

pcreview forum

そしてついに、私は msdn documentation を本当に見つけました。

従来、VBAプログラマは、必要なメモリが少ないため、整数を使用して小さな数値を保持していました。ただし、最近のバージョンでは、VBAは整数型として宣言されている場合でも、すべての整数値をLong型に変換します。そのため、整数変数を使用することによるパフォーマンス上の利点はなくなりました。実際、VBAは変数を変換する必要がないため、Long変数はわずかに高速になる場合があります。

したがって、要約すると、最近Integerタイプを使用する正当な理由はほとんどありません。 Unless16ビット整数を期待する古いAPI呼び出しと相互運用する必要がある場合を除きます。

指摘する価値のあることの1つは、一部の古いAPI関数は16ビット(2バイト)整数のパラメーターを期待している可能性があり、32ビットであり、整数(すでに4バイトの長さ)を渡そうとしている場合参照により、バイト長の違いにより機能しません。

それを指摘してくれたVba4Allに感謝します。

116
RubberDuck

他の回答で述べたように、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またはその他の言語に移行するときは、int16int32およびint64これらのデータ型に保持できる値について、より透明性を高める必要があります。

12
Patrick

VBAには多くの歴史的な荷物があります。

Integerは16ビット幅であり、16ビットアーキテクチャ/ワードサイズが普及しているときは、デフォルトの数値型として適切でした。

Longは32ビット幅であり、可能な限り(IMO)を使用する必要があります。

7
Alex K.

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

Longは最も高速に動作したため、Longの代わりにIntegerを常に使用するというMicrosoftの推奨事項が理にかなっていると考えなければなりません。 Byteでもtrueと同じように推測しますが、ほとんどのコーダーはこれを使用しません。

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
6
PGSystemTester

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

状況によっては、ロングを使用するのは必要性です。大きなExcelファイルで行をループしている場合、行番号を保持する変数は長いはずです。

ただし、整数で問題を処理でき、longを使用するとスペース(メモリ)が無駄になることがわかっている場合があります。個々の変数が実際に大きな違いを生むことはありませんが、配列の取り扱いを開始すると、大きな違いを生むことができます。

  • VBA7では、整数は2バイトで、長整数は4バイトです

  • 整数配列を使用すると、1〜10の100万個の配列がある場合、約4MBの_と比較して、2MBのRAMを使用しますaboutRAM長い配列の場合。

4
Alter

@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
1
AJD

既に述べたように、LongmayIntegerの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は、自分自身の大小の定義を区別するためだけに使用します。

0
Ama