Как вы получаете VB6 для инициализации двойного с + бесконечность, -infinity и NaN? - PullRequest
8 голосов
/ 20 мая 2009

VB6, кажется, не позволяет легко хранить + бесконечность, -infinity и NaN в двойных переменных. Было бы полезно, если бы это было так, чтобы я мог сделать сравнения с этими значениями в контексте комплексных чисел. Как?

Ответы [ 3 ]

19 голосов
/ 20 мая 2009

На самом деле, есть НАМНОГО более простой способ получить бесконечность, бесконечность и не число:

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
13 голосов
/ 22 мая 2009

Несколько разных вещей. Как вы можете видеть из примера Pax, вам просто нужно посмотреть стандарт IEEE 754, а затем подключить ваши байты в нужных местах. Единственное предупреждение, которое я хотел бы дать вам, это то, что MicroSoft устарела как RtlMoveMemory из-за его потенциальной возможности создавать проблемы безопасности типа переполнения. В качестве альтернативы вы можете выполнить это в «чистом» VB с небольшим осторожным принуждением, используя пользовательские типы и LSet. (Также обратите внимание, что существует два типа NaN.)

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
4 голосов
/ 20 мая 2009

Эта страница показывает немного мучительный способ сделать это. Я сократил его, чтобы соответствовать тому, о чем просил ваш вопрос, но не проверил полностью. Дайте мне знать, если есть какие-либо проблемы. Одна вещь, которую я заметил на этом сайте, состоит в том, что код, который они имели для тихого 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

Он в основном использует копии памяти уровня ядра для передачи битовых комбинаций из байтового массива в двойной.

Следует помнить, однако, что есть несколько битовых значений, которые могут представлять QNaN, в частности, бит знака может быть 0 или 1, и все биты мантиссы, кроме первого, также могут быть равны нулю. или 1. Это может усложнить вашу стратегию для сравнений, если вы не сможете обнаружить, использует ли VB6 только один из битовых шаблонов - однако это не повлияет на инициализацию этих значений, если допустить, что VB6 правильно реализует двойные значения IEE754.

...