Search code examples
vbaexcelfloating-pointdoublefloating-point-conversion

Extract mantissa, exponent and sign data from IEEE-754 double in VBA


How to extract mantissa, exponent and sign data from an IEEE-754 64-bit (double) floating-point number in VBA? Thanks

Edit (after John Coleman comments). Before posting the original question, I have looked around for a solution and could only find how to do it in C (e.g. using structures with bit fields). Couldn't find anything for VBA. I have tried using VBA's bit operators (i.e. AND, OR, NOT, XOR) but this does not seem to give the expected result. For example, 1 expressed in single precision IEEE 32-bit floating-point is represented by

0 01111111 00000000000000000000000

where the first bit is for sign, the next 8 bits are for the (biased) exponent, and the last 23 bits are for the mantissa. Applying NOT to 1 should return

1 10000000 11111111111111111111111

which is -3.9999998 in decimal, but the following code in VBA returns -2, which is represented by

1 10000000 00000000000000000000000

x = Not 1!
Debug.Print x

I didn't see the point of posting this in my OP.


Solution

  • I think I've found the way to do this. The following function DoubleToBin returns a string of 64 bits representing an IEEE-754 double floating-point number. It uses a VBA "trick" to pass around raw data without using API routines (such as MemCopy (RtlMoveMemory)) by combining LSet with User Defined Types of the same size. And once we have the bit string we can extract all components from it.

    Type TDouble
      Value As Double
    End Type
    
    Type TArray
      Value(1 To 8) As Byte
    End Type
    
    Function DoubleToArray(DPFloat As Double) As Variant
      Dim A As TDouble
      Dim B As TArray
      A.Value = DPFloat 
      LSet B = A
      DoubleToArray = B.Value
    End Function
    
    Function DoubleToBin(DPFloat As Double) As String
      Dim ByteArray() As Byte
      Dim BitString As String
      Dim i As Integer
      Dim j As Integer
    
      ByteArray = DoubleToArray(DPFloat)
    
      For i = 8 To 1 Step -1
        j = 2 ^ 7
        Do While j >= 1
          If (ByteArray(i) And j) = 0 Then
            BitString = BitString & "0"
          Else
            BitString = BitString & "1"
          End If
          j = j \ 2
        Loop
      Next i
    
      DoubleToBin = BitString
    End Function
    

    How does it work on here - do I now accept my own answer?