VBAで正の無限大・負の無限大を取得する方法のメモです。
はじめに
VBAの組み込み型の一つのDouble データ型は、通常のVBAの操作の範囲内では、有限の小数しか扱うことができません。
しかし、Double型はVBA独自の表現では無く、他のプログラミング言語で使われている倍精度浮動小数点数と同じ表現のため、正の無限大や負の無限大、非数などを値として持つことができます。
この記事ではDouble型に正の無限大や負の無限大、非数を設定する方法を記載します。
参考
VBAのDouble型のページには
IEEE 64 ビット (8 バイト) 浮動小数点数
と記載があり、
この資料の15ページには
All valid IEEE 754-1985 double-precision binary
floating-point numbers including sized zeros, NaNs and
infinities
とあり、IEEE 754-1985に準拠しているとなっています。
コード
実際に正の無限大・負の無限・非数を取得するコードです。
以下のコードのPositiveInfinity
・NegativeInfinity
・NaN
プロシージャの値が、それぞれ正の無限大・負の無限・非数となります。
'モジュール宣言部
'LSetでDouble型の中身を書き換えるため、
'Double型および8バイト分(=Double型の大きさ)Byte配列をもつユーザー定義型を用意する・
Private Type udtByte8
Value(0 To 7) As Byte
End Type
Private Type udtDouble
Value As Double
End Type
'正の無限大を取得する。
Public Property Get PositiveInfinity() As Double
Dim uB8 As udtByte8
Dim uDb As udtDouble
'念のため大きさチェック。
Debug.Assert (Len(uB8) = 8) And (Len(uDb) = 8)
With uB8
.Value(UBound(.Value) - 1) = 240
.Value(UBound(.Value)) = 127
End With
LSet uDb = uB8
Let PositiveInfinity = uDb.Value
End Property
'負の無限大を取得する。
Public Property Get NegativeInfinity() As Double
Dim uB8 As udtByte8
Dim uDb As udtDouble
'念のため大きさチェック。
Debug.Assert (Len(uB8) = 8) And (Len(uDb) = 8)
With uB8
.Value(UBound(.Value) - 1) = 240
.Value(UBound(.Value)) = 255
End With
LSet uDb = uB8
Let NegativeInfinity = uDb.Value
End Property
'非数(Not a Number)を取得する。
Public Property Get NaN() As Double
Dim uB8 As udtByte8
Dim uDb As udtDouble
'念のため大きさチェック。
Debug.Assert (Len(uB8) = 8) And (Len(uDb) = 8)
With uB8
.Value(UBound(.Value) - 1) = 248
.Value(UBound(.Value)) = 255
End With
LSet uDb = uB8
Let NaN = uDb.Value
End Property
コードの解説
「正の無限大」などは、Double型の中身が特定のパターンとなったときを示しています。
そのため、そのパターンとなるようにDouble型の中身を書き換えれば「正の無限大」などが得られることになります。
書き換える方法
上記のコードでは、LSet ステートメントを使って中身を書き換えています。
ユーザー定義型を対象にLSetを使用すると、中の型をスルーしてバイナリでデータのコピーが行われます。
上記のコードではDouble型のみを要素として持つudtDouble
に、Double型と同じ大きさのByte型配列を持つudtByte8
をコピーすることで、中身を書き換えています。
(参考)「特定のパターン」の調べ方
倍精度浮動小数点数内にも記載があったりと、ネットで調べればすぐに出てきますが、
PowerShellなどを使って実際に調べることもできます。
例えば以下のコードは、正の無限大・負の無限大・非数について、バイト毎に分解した情報をコンソールに表示します。
@(
'PositiveInfinity'
'NegativeInfinity'
'NaN'
) | ForEach-Object -Process {
$_
[System.BitConverter]::GetBytes([double]::$_) -join ","
}
PositiveInfinity
0,0,0,0,0,0,240,127
NegativeInfinity
0,0,0,0,0,0,240,255
NaN
0,0,0,0,0,0,248,255
他の方法
Win32 APIなどで、Double型の中身を直接書き換えても、可能なはずです(未検証)。
また、JScriptであればNumber.POSITIVE_INFINITY
などで取得できるため、JScript経由で取得する方法もあります。
VBAからJScriptのfunctionオブジェクトを使用する(64bit対応) - QiitaのJSFunc
を使用した例
Public Property Get PositiveInfinity()
Let PositiveInfinity = JSFunc("", "Number.POSITIVE_INFINITY")(Empty)
End Property
参考ページ
Double データ型 | Microsoft Docs (VBAのDouble型)
[MS-VBAL].pdf
Double Struct (System) | Microsoft Docs (.NETのDouble型)
倍精度浮動小数点数 - Wikipedia
IEEE 754 - Wikipedia
LSet ステートメント (VBA) | Microsoft Docs