VB6 không xuất hiện để làm cho nó dễ dàng để lưu trữ + vô cùng, -infinity và NaN vào đôi vars. Nó sẽ giúp ích nếu nó có thể để tôi có thể so sánh với các giá trị đó trong bối cảnh các số phức. Làm sao?Làm thế nào để bạn nhận được VB6 để khởi tạo đôi với + vô cùng, -infinity và NaN?
Trả lời
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
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.
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
Đó 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
Tôi không chắc chắn có nên cười hay xấu hổ hay không. – bugmagnet
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
+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
+1 Điều đó hoàn toàn tuyệt vời –
'Debug.Print -lfNaN' cho' 1. # QNAN', mà tôi giả định là NaN "yên tĩnh" (?). – Andre
Đây là công cụ cực kỳ tuyệt vời. Cảm ơn rất nhiều vì đã chia sẻ nó. – bugmagnet