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.
eg.
dim x as Double
x = 345678890 ' or any large number
? x And 2 ^ 60
This is currently resulting in an overflow.
Whoops, that last example should have been:
If MyInt and -(2^15) then
Msgbox "Bit is set"
else
Msgbox "Bit is clr"
endif
If MyInt and -(2^15) then
Msgbox "Bit is set"
else
Msgbox "Bit is clr"
endif
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
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
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
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
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 !
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.
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
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.
'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.
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>10001000 10001001<E TX>
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.
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>10001000
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...
Until next time...
ASKER
Thanks again for your input. It's been really valuable, not to mention how quick your responses have been.
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