Link to home
Start Free TrialLog in
Avatar of woka
woka

asked on

Bitwise Operations on Single, Double or Decimal types ?

Is it possible to perform bitwise operations on types other than byte, integer or long ?

eg.

dim x as Double

x = 345678890 ' or any large number

? x And 2 ^ 60

This is currently resulting in an overflow.
Avatar of mrmick
mrmick

You bet.

But you can't check for a bit that doesn't exist.  You must remember the size of the data type:

Byte = 8 bits
Integer = 16 bits
Long = 32 bits
Double = 64 bits

*** AND ***
When you're checking the sign bit of an integer or long - the bit value must be negative.  For example, to check bit 15 of an integer... Use the following:

If MyInt and 1(2^15) then
  Msgbox "Bit is set"
else
  Msgbox "Bit is clr"
endif

Whoops, that last example should have been:



If MyInt and -(2^15) then
  Msgbox "Bit is set"
else
  Msgbox "Bit is clr"
endif
Avatar of woka

ASKER

Given your answer, the example I gave should work.  Instead it results in an overflow error.  Any more ideas ?

Sorry woka, the bit values of a floating type (double or single) are comprised of a sign bit, mantissa bits and exponent bits.  You really can only effectively test bit values of integers.

While Bit 60 exists, 2^60 is a larger value than a double can store precisely.  To answer your question, Bit 60 in the 64 bits that make up a double would have to be tested as follows:

If 2 ^ 28 And x Then
  Print "Bit 60 is Set"
Else
  Print "Bit 60 is Clr"
End If

Avatar of woka

ASKER

Sorry to keep coming back about this (not sure if I should keep reopening the question either, is that the right protocol) but how did you derive the 28 in 2 ^ 28 ?

ASKER CERTIFIED SOLUTION
Avatar of mrmick
mrmick

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of woka

ASKER

Excellent !!  Thanks for your help with this, it's going to make my life a lot easier.  FYI, the application I am using it with is taking data from a UPS where each bit in a series of bytes represents an event.  There are a total of 74 possible events.  While I can use a UDT to manipulate the info, I also have to pass it using COM where UDT's are a no go.  Passing a variant containing a Decimal data type is a lot more practical than having to deal with a bunch of bytes or integers or longs (I've had a quick bash modifying your code and it doesn't really like me using a variant, but I'll find a way around this).

I spent some time last night pouring over some old fortran doco on IEEE formats but didn't really get anywhere.  The solution you've given me will help imensely (sp?).  Thanks again.

PS.  Isn't LSet a useful little thing !

No problem, If you let me know how many bits are in your data type, I can probably show you an even easier way of passing the data.  Furthermore, you're best bet is to create a class to handle this.  I have an appointment right now (will take most of the evening), but when I return, If you've given me more details, I'll try to work out an example for you.  Give me an example of your call passing the data too.
Avatar of woka

ASKER

I am planning on using a double or decimal data type.  In a variant, the doco states that double is 16 bytes and decimal is 12 or 14 bytes depending on where you look.  It would be nice to use a "normal" way of checking bits like:

if varDouble And &H4000000 then

but since this will (I suspect) result in overflow I suppose a series of functions as follows would work best:

varDecimal = SetBit(varDecimal as Variant, BitNumber as Integer, bSet as Boolean)

bSet = IsBitSet(varDecimal as Variant, BitNumber as Integer)

The variable (I've been using a variant with a long data type for testing) is already contained within a class (and collection) with all the other UPS data.  Is this what you meant ?

TIA

I was going to carry it a bit further (no pun intended).  For example, if bits 0 - 5 indicated the Week of the Year, and bit 6 indicated AM or PM, I might expose the following properties:

'Class level array declaration.
Dim Bits(0 to 15) as byte ‘Array of bytes containing 16 bytes of bits (128 bits)

Property Get WeekOfYear() As Long 'Could be Integer, or even Byte
   DayOfWeek = Bits(0) And &H3F
End Property

Property Let DayOfWeek(NewValue As Long)
   Bits(0) = (Bits(0) And &HC0) Or (NewValue And &H3f)
End Property

Property Get IsAM() As Boolean
   IsAM = Bits(0) And &H40H
End Property

Property Let IsAm(NewValue as boolean)
   Bits(0) = (Bits(0) And &HBF) Or (NewValue And &H40)
End Property

And so on...

I still have no idea what method you’re using to pass the bit info so I can’t make a suggestion.  If you posted the method you’re using to pass the bit data, I would likely see a good solution to that problem.

Avatar of woka

ASKER

This may need a bit of explanation.

The UPS is sending information to the PC (via a serial port) in ASCII packets.  There are several different types of packets containing different information, but the one I'm dealing with here is as follows:

<SOH><HEADER><STX>1000100010001001<ETX>

Each 1 or 0 represents an event currently happening on the UPS. eg. The first 1 represents the event "Mains Failure".  If it is 1, the mains supply has failed and if it's 0 the mains is OK.

I'm just taking the ASCII string and storing it in a variable where each bit represents an event.

The method used to pass the info is like this:

Sub UpdateEvents(vEvents as Variant)

The variant would presumably be of type double or decimal.

Given that each bit is has an individual purpose rather than being combined with other bits, I'm not sure the method you have shown above is applicable.

Having said that, the penny has dropped with what you are doing and I can see a lot of applications for it that I wouldn't have thought to deal with that way before.  I obviously didn't write enough Fortran !

Am I on the right track ?  Let me know if you still think there is an application for what you presented above.  TIA.
Hmmm... I think so (by the way, I haven't written any Fortran since 1982).  I think I'm going to put this to rest...  I didn't realize you were communicating through a serial port; I thought you were working with a DLL interface that handled communications with the UPS.  My mistake.

Until next time...
Avatar of woka

ASKER

Thanks again for your input.  It's been really valuable, not to mention how quick your responses have been.