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.
LVL 2
Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Commented:
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

0
Commented:
Whoops, that last example should have been:

If MyInt and -(2^15) then
Msgbox "Bit is set"
else
Msgbox "Bit is clr"
endif
0
Author Commented:
Given your answer, the example I gave should work.  Instead it results in an overflow error.  Any more ideas ?

0
Commented:
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

0
Author Commented:
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 ?

0
Commented:
Whoops, I that was the 64th bit I set.  Here is example code that sets the 60th bit and displays the resulting number in the debug (immediate) window.  Create a new project and paste this code into the project.

'The eight bytes that make up a double
Private Type DoubleBytes
B0 As Byte
B1 As Byte
B2 As Byte
B3 As Byte
B4 As Byte
B5 As Byte
B6 As Byte
B7 As Byte
End Type

'A Double
Private Type MyDouble
dbl As Double
End Type

Private Sub Form_Load()

Dim db As DoubleBytes
Dim mydbl As MyDouble

'Set the 60th bit (range = 0 to 63)
db.B7 = 16

'Copy the bytes to the double.
LSet mydbl = db

'Display the result
Debug.Print mydbl.dbl

End Sub

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Author Commented:
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 !

0
Commented:
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.
0
Author Commented:
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

0
Commented:
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.

0
Author Commented:
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.
0
Commented:
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...
0
Author Commented:
Thanks again for your input.  It's been really valuable, not to mention how quick your responses have been.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Visual Basic Classic

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.