9

VB6では、+ infinity、-infinity、およびNaNをdoublevarsに簡単に格納できるようには見えません。複素数のコンテキストでこれらの値と比較できるようになれば、役に立ちます。どのように?

4

3 に答える 3

20

実際には、無限大を取得するためのはるかに簡単な方法があります。-無限大であり、数値ではありません。

public lfNaN    as Double ' or As Single
public lfPosInf as Double
public lfNegInf as Double

on error resume next    ' to ignore Run-time error '6': Overflow and '11': Division by zero
lfNaN    =  0 / 0       ' -1.#IND
lfPosInf =  1 / 0       '  1.#INF
lfNegInf = -1 / 0       ' -1.#INF

on error goto 0         ' optional to reset the error handler
于 2009-05-20T04:37:26.940 に答える
14

いくつかの異なるもの。Paxの例からわかるように、実際にはIEEE 754標準を調べて、バイトを適切な場所に接続する必要があります。私があなたに与える唯一の注意は、オーバーフロータイプのセキュリティ問題を引き起こす可能性があるため、 MicroSoftがRtlMoveMemoryを非推奨にしたことです。別の方法として、ユーザー定義タイプとLSetを使用して、少し注意深く強制することで、「純粋な」VBでこれを実現できます。(NaNには2つのタイプがあることにも注意してください。)

Option Explicit

Public Enum abIEEE754SpecialValues
    abInfinityPos
    abInfinityNeg
    abNaNQuiet
    abNaNSignalling
    abDoubleMax
    abDoubleMin
End Enum

Private Type TypedDouble
    value As Double
End Type

Private Type ByteDouble
    value(7) As Byte
End Type

Public Sub Example()
    MsgBox GetIEEE754SpecialValue(abDoubleMax)
End Sub

Public Function GetIEEE754SpecialValue(ByVal value As abIEEE754SpecialValues) As Double
    Dim dblRtnVal As Double
    Select Case value
    Case abIEEE754SpecialValues.abInfinityPos
        dblRtnVal = BuildDouble(byt6:=240, byt7:=127)
    Case abIEEE754SpecialValues.abInfinityNeg
        dblRtnVal = BuildDouble(byt6:=240, byt7:=255)
    Case abIEEE754SpecialValues.abNaNQuiet
        dblRtnVal = BuildDouble(byt6:=255, byt7:=255)
    Case abIEEE754SpecialValues.abNaNSignalling
        dblRtnVal = BuildDouble(byt6:=248, byt7:=255)
    Case abIEEE754SpecialValues.abDoubleMax
        dblRtnVal = BuildDouble(255, 255, 255, 255, 255, 255, 239, 127)
    Case abIEEE754SpecialValues.abDoubleMin
        dblRtnVal = BuildDouble(255, 255, 255, 255, 255, 255, 239, 255)
    End Select
    GetIEEE754SpecialValue = dblRtnVal
End Function

Public Function BuildDouble( _
    Optional byt0 As Byte = 0, _
    Optional byt1 As Byte = 0, _
    Optional byt2 As Byte = 0, _
    Optional byt3 As Byte = 0, _
    Optional byt4 As Byte = 0, _
    Optional byt5 As Byte = 0, _
    Optional byt6 As Byte = 0, _
    Optional byt7 As Byte = 0 _
    ) As Double
    Dim bdTmp As ByteDouble, tdRtnVal As TypedDouble
    bdTmp.value(0) = byt0
    bdTmp.value(1) = byt1
    bdTmp.value(2) = byt2
    bdTmp.value(3) = byt3
    bdTmp.value(4) = byt4
    bdTmp.value(5) = byt5
    bdTmp.value(6) = byt6
    bdTmp.value(7) = byt7
    LSet tdRtnVal = bdTmp
    BuildDouble = tdRtnVal.value
End Function

最後に、次の方法でNaNを取得することもできます。

Public Function GetNaN() As Double
    On Error Resume Next
    GetNaN = 0 / 0
End Function
于 2009-05-22T04:04:10.130 に答える
4

このページは、それを行うための少し厄介な方法を示しています。私はあなたの質問が求めたものと一致するようにそれを切り詰めましたが、徹底的にテストしていません。問題があれば教えてください。そのサイトで私が気づいたことの1つは、静かなNaNのコードが間違っていたことです。仮数を1ビットで開始する必要があります。つまり、NaNのシグナリングと混同されているようです。

Public NegInfinity As Double
Public PosInfinity As Double
Public QuietNAN As Double

Private Declare Sub CopyMemoryWrite Lib "kernel32" Alias "RtlMoveMemory" ( _
    ByVal Destination As Long, source As Any, ByVal Length As Long)

' IEEE754 doubles:                                                          '
'   seeeeeee eeeemmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm '
'   s = sign                                                                '
'   e = exponent                                                            '
'   m = mantissa                                                            '
'   Quiet NaN: s = x, e = all 1s, m = 1xxx...                               '
'   +Inf     : s = 0, e = all 1s, m = all 0s.                               '
'   -Inf     : s = 1, e = all 1s, m = all 0s.                               '

 

Public Sub Init()
    Dim ptrToDouble As Long
    Dim byteArray(7) As Byte
    Dim i As Integer

    byteArray(7) = &H7F
    For i = 0 To 6
        byteArray(i) = &HFF
    Next
    ptrToDouble = VarPtr(QuietNAN)
    CopyMemoryWrite ptrToDouble, byteArray(0), 8

    byteArray(7) = &H7F
    byteArray(6) = &HF0
    For i = 0 To 5
        byteArray(i) = 0
    Next
    ptrToDouble = VarPtr(PosInfinity)
    CopyMemoryWrite ptrToDouble, byteArray(0), 8

    byteArray(7) = &HFF
    byteArray(6) = &HF0
    For i = 0 To 5
        byteArray(i) = 0
    Next
    ptrToDouble = VarPtr(NegInfinity)
    CopyMemoryWrite ptrToDouble, byteArray(0), 8
End Sub

基本的に、カーネルレベルのメモリコピーを使用して、ビットパターンをバイト配列からdoubleに転送します。

ただし、 QNaNを表すことができる複数のビット値があることに注意してください。具体的には、符号ビットは0または1であり、仮数の最初のビット以外のすべてのビットも0または1である可能性があります。これにより、戦略が複雑になる可能性があります。 VB6がビットパターンの1つのみを使用するかどうかを検出できない限り、比較します。ただし、VB6がIEE754 doubleを適切に実装していると仮定すると、これらの値の初期化には影響しません。

于 2009-05-20T03:34:20.747 に答える