2009-05-20 26 views

Trả lời

12

Một vài điều khác nhau. Như bạn có thể thấy từ ví dụ của Pax, bạn thực sự chỉ cần tra cứu chuẩn IEEE 754 và sau đó cắm các byte của bạn vào đúng vị trí. Sự thận trọng duy nhất tôi sẽ cung cấp cho bạn là MicroSoft has deprecated RtlMoveMemory do có khả năng tạo ra các vấn đề bảo mật của loại tràn. Như một sự thay thế, bạn có thể thực hiện điều này trong VB "tinh khiết" với một chút ép buộc cẩn thận bằng cách sử dụng User Defined Types và LSet. (Cũng lưu ý rằng có hai loại 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 

Một ngoái mặt lưu ý, bạn cũng có thể nhận NaN theo cách này:

Public Function GetNaN() As Double 
    On Error Resume Next 
    GetNaN = 0/0 
End Function 
+0

Đây là công cụ cực kỳ tuyệt vời. Cảm ơn rất nhiều vì đã chia sẻ nó. – bugmagnet

4

This page hiển thị một cách hơi mạo hiểm để thực hiện điều đó. Tôi đã cắt nó xuống để phù hợp với những gì câu hỏi của bạn yêu cầu nhưng chưa được kiểm tra kỹ lưỡng. Hãy cho tôi biết nếu có bất kỳ vấn đề gì. Một điều tôi nhận thấy trên trang web đó là mã họ đã có cho một NaN yên tĩnh là sai, nó sẽ bắt đầu mantissa với 1-bit - họ dường như đã nhận được rằng nhầm lẫn với một tín hiệu 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 

Về cơ bản nó sử dụng bản sao bộ nhớ kernel cấp để chuyển các mẫu bit từ một mảng byte để được cú đúp. Tuy nhiên, bạn nên nhớ rằng có bit-giá trị có thể đại diện cho QNaN, cụ thể bit dấu có thể là 0 hoặc 1 và tất cả các bit của mantissa khác với giá trị đầu tiên cũng có thể bằng 0 hoặc 1. Điều này có thể làm phức tạp chiến lược của bạn để so sánh trừ khi bạn có thể khám phá nếu VB6 chỉ sử dụng một trong các mẫu bit - nó sẽ không ảnh hưởng đến việc khởi tạo các giá trị đó, giả sử VB6 thực hiện đúng IEE754 gấp đôi.

+0

Vì vậy, bạn đang liên kết đến blog questionner gốc, nơi ông đã đăng một mục với đâm tốt nhất của mình một ngày trước khi đặt câu hỏi? Đủ công bằng, nó thật là vui! – MarkJ

+0

Đó không chỉ là thú vị, nó vui nhộn. Tôi đã không thực sự biết người hỏi là chủ sở hữu của blog đó vào thời điểm đó, nhưng có biệt danh stackoverflow của mình ngay trên blog :-) Tôi đang trong hai suy nghĩ về việc liệu để xóa câu trả lời này hay không. Nếu không có gì khác, nó có thể cung cấp một số giải trí cho người khác. – paxdiablo

+0

Tôi không chắc chắn có nên cười hay xấu hổ hay không. – bugmagnet

17

Trên thực tế, có một cách đơn giản để có được NHIÊU Infinity, vô cực và Not a Number:

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 
+0

+1 Tôi chưa bao giờ biết điều đó trước đây! Có vẻ như bạn cũng có thể nhận NAN bằng cách đánh giá 0/0? Dù sao, Debug.Print nói rằng đó là -1. # IND khác với 1. # INF mà tôi nhận được từ 1/0. Tôi cho rằng đó là NAN. – MarkJ

+0

+1 Điều đó hoàn toàn tuyệt vời –

+0

'Debug.Print -lfNaN' cho' 1. # QNAN', mà tôi giả định là NaN "yên tĩnh" (?). – Andre

Các vấn đề liên quan