LoginSignup
4
1

More than 3 years have passed since last update.

VBAで正の無限大・負の無限大を取得する

Posted at

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に準拠しているとなっています。

コード

実際に正の無限大・負の無限・非数を取得するコードです。

以下のコードのPositiveInfinityNegativeInfinityNaNプロシージャの値が、それぞれ正の無限大・負の無限・非数となります。

'モジュール宣言部
    '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対応) - QiitaJSFuncを使用した例

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

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1