| View previous topic :: View next topic |
| Author |
Message |
SKAN
Joined: 26 Dec 2005 Posts: 5882
|
Posted: Tue Jun 19, 2007 11:50 am Post subject: Help required on Bitwise operation |
|
|
I have a situation where I expect an Integer value of 128 but getting a wrong value of 2147483776 instead!
When I inspect the bits, I find that the Most Significant Bit is ON ( for me it is wrongly signed?! ) .
How to set the Most Significant Bit OFF if it is ON ?
| Code: | cInt := 128 ; Correct
wInt := 2147483776 ; Wrong
MsgBox, % "Correct:`t" NumToBits( cInt, 32 )
. "`nWrong:`t" NumToBits( wInt, 32 )
NumToBits( Num=0, bits=32 ) {
Loop %bits%
bin := bin ( Num >> ( bits - A_Index) & 1)
Return bin
} |
Please help!  |
|
| Back to top |
|
 |
Dippy46
Joined: 06 Jul 2004 Posts: 171 Location: Manchester, England.
|
Posted: Tue Jun 19, 2007 12:29 pm Post subject: |
|
|
@ Skan
The short answer is any of the following:
| Code: |
no1 := 2147483776 ^ 0x80000000 ; hex way
no2 := 2147483776 ^ 2**31 ; use bit position
no3 := 2147483776 ^ 2147483648 ; decimal way
msgbox % no1 " " no2 " " no3
|
though obviously for clarity it's better to use the bit position.
If you're using this in a situation where you are defining the variable type
then make sure you're using UINT instead of INT because INT is always
going to return a signed result !
Regards Dave. _________________ Simple ideas lie within reach, only of complex minds |
|
| Back to top |
|
 |
SKAN
Joined: 26 Dec 2005 Posts: 5882
|
Posted: Tue Jun 19, 2007 2:14 pm Post subject: |
|
|
@Dippy46
Thank you very much Sir!
| Quote: | | though obviously for clarity it's better to use the bit position |
One more related question: How to turn OFF first 6 bits from the left ?
 |
|
| Back to top |
|
 |
Helpy Guest
|
Posted: Tue Jun 19, 2007 3:19 pm Post subject: |
|
|
Should be something like:
x &= 0x03FFFFFF |
|
| Back to top |
|
 |
SKAN
Joined: 26 Dec 2005 Posts: 5882
|
Posted: Tue Jun 19, 2007 4:08 pm Post subject: |
|
|
It works! Many thanks Helpy!
| Code: | Int1 := 0xFFFFFFFF ; Set all bits ON
Int2 := Int1 & 0x03FFFFFF ; Set first 6 bits OFF
MsgBox, % NumToBits(Int1) "`n" NumToBits(Int2)
NumToBits( Num=0, bits=32 ) {
Loop %bits%
bin := bin ( Num >> ( bits - A_Index) & 1)
Return bin
} |
Regards,  |
|
| Back to top |
|
 |
foom
Joined: 19 Apr 2006 Posts: 386
|
Posted: Tue Jun 19, 2007 4:20 pm Post subject: |
|
|
| You could have done x:=(x<<6)>>6 but the & methond is faster and enables you to clear bytes in any range you like. Btw if you are unsure about how to convert a bitchain to the dezimal/hex value. You can use calc.exe in scientific mode to do this. Run calc, select scientific mode from the view menupoint, click the Bin radiobutton, type your bitchain, click the Hex radiobutton, and voila. |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4015 Location: Pittsburgh
|
Posted: Tue Jun 19, 2007 4:29 pm Post subject: |
|
|
Instead of Dippy46's XOR solution, bitwise AND is safer, as Helpy described. It clears the desired bits, while the XOR version flips them (if they were not set, they will be, afterwards).
To get the desired mask from a few bit positions to clear, do this | Code: | MsgBox % MakeMask(32-6)
MakeMask(bit1="",bit2="",bit3="",bit4="",bit5="") {
mask = 0xFFFFFFFF ; -1 for 64-bit masks
Loop {
i := SubStr(A_Index,0) ; needed with SetFormat Integer, Hex
IfEqual bit%i%,, Break
mask ^= 1 << bit%i%
}
Return mask
} | To clear only bit6 from the left of 32-bit integers, the mask is 0xFBFFFFFF.
Last edited by Laszlo on Tue Jun 19, 2007 4:36 pm; edited 1 time in total |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4015 Location: Pittsburgh
|
Posted: Tue Jun 19, 2007 4:36 pm Post subject: |
|
|
| foom wrote: | | You could have done x:=(x<<6)>>6 | It works only for 64-bit numbers, and only if bit58 was 0 originally. This technique is a clever way to do 64-bit sign extension. |
|
| Back to top |
|
 |
Titan
Joined: 11 Aug 2004 Posts: 5068 Location: imaginationland
|
Posted: Tue Jun 19, 2007 4:38 pm Post subject: |
|
|
Did everyone forget ToBin() lol. :/ _________________
RegExReplace("irc.freenode.net/ahk", "^(?=(.(?=[\0-r\[]*((?<=\.).))))(?:[c-\x73]{2,8}(\S))+((2)|\b[^\2-]){2}\D++$", "$u3$1$3$4$2") |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4015 Location: Pittsburgh
|
Posted: Tue Jun 19, 2007 4:46 pm Post subject: |
|
|
| ...and all the other, better versions posted before that? |
|
| Back to top |
|
 |
Titan
Joined: 11 Aug 2004 Posts: 5068 Location: imaginationland
|
Posted: Tue Jun 19, 2007 5:12 pm Post subject: |
|
|
I got the idea from Jon (the first) and posted on his thread. More specifically, my function does the bit shifting Skan needed to know. _________________
RegExReplace("irc.freenode.net/ahk", "^(?=(.(?=[\0-r\[]*((?<=\.).))))(?:[c-\x73]{2,8}(\S))+((2)|\b[^\2-]){2}\D++$", "$u3$1$3$4$2") |
|
| Back to top |
|
 |
SKAN
Joined: 26 Dec 2005 Posts: 5882
|
Posted: Tue Jun 19, 2007 6:03 pm Post subject: |
|
|
This help topic has reference to my code posted here : http://www.autohotkey.com/forum/viewtopic.php?p=98203#98203
When A CD/DVD is inserted in a drive, WM_DEVICECHANGE is broadcast with with wParam as 0x8000 ( DBT_DEVICEARRIVAL ) and lParam will be a pointer to DEV_BROADCAST_VOLUME stucture.
The 4th member of DEV_BROADCAST_VOLUME stucture is dbcv_unitmask, a DWord whose bits have to be evaluated to ascertain the CD/DVD drive letter.
dbcv_unitmask should contain integers for respective drive letters as follows:
| Code: | A = 00000000000000000000000000000001 = 1
B = 00000000000000000000000000000010 = 2
C = 00000000000000000000000000000100 = 4
D = 00000000000000000000000000001000 = 8
E = 00000000000000000000000000010000 = 16
F = 00000000000000000000000000100000 = 32
G = 00000000000000000000000001000000 = 64
H = 00000000000000000000000010000000 = 128
I = 00000000000000000000000100000000 = 256
J = 00000000000000000000001000000000 = 512
K = 00000000000000000000010000000000 = 1024
L = 00000000000000000000100000000000 = 2048
M = 00000000000000000001000000000000 = 4096
N = 00000000000000000010000000000000 = 8192
O = 00000000000000000100000000000000 = 16384
P = 00000000000000001000000000000000 = 32768
Q = 00000000000000010000000000000000 = 65536
R = 00000000000000100000000000000000 = 131072
S = 00000000000001000000000000000000 = 262144
T = 00000000000010000000000000000000 = 524288
U = 00000000000100000000000000000000 = 1048576
V = 00000000001000000000000000000000 = 2097152
W = 00000000010000000000000000000000 = 4194304
X = 00000000100000000000000000000000 = 8388608
Y = 00000001000000000000000000000000 = 16777216
Z = 00000010000000000000000000000000 = 33554432
[ = 00000100000000000000000000000000 = 67108864
\ = 00001000000000000000000000000000 = 134217728
] = 00010000000000000000000000000000 = 268435456
^ = 00100000000000000000000000000000 = 536870912
_ = 01000000000000000000000000000000 = 1073741824
` = 10000000000000000000000000000000 = 2147483648 |
My DVD-Writer shows as H: in explorer so I expect dbcv_unitmask to be 128, whereas it is 2147483776 for me in Windows 2000 SP4. Inspecting the bits, I find the MSB is ON making it a signed integer!
My previous code runs flawlessly in Windows 98 SE and Windows XP Pro ( SP 2) but troubles me with the said effect in Windows 2000
To workaround this effect, I have the choice of
1) Setting the first 6 bits of dbcv_unitmask to be zero
2) Scan bits of dbcv_unitmask from LSB to MSB, find the first bit ON and ignore the rest.
I opted for the 2nd and here is the code: ( requires 1.0.47+ )
Ascertaining drive letter on CD/DVD insert notification:
| Code: | OnMessage( 0x219, "WM_DEVICECHANGE" )
Return
WM_DEVICECHANGE( wParam, lParam ) { ; http://msdn2.microsoft.com/en-us/library/aa363480.aspx
Global Drv
Static DBT_DEVICEARRIVAL := 0x8000 ; http://msdn2.microsoft.com/en-us/library/aa363205.aspx
Static DBT_DEVTYP_VOLUME := 0x2 ; http://msdn2.microsoft.com/en-us/library/aa363246.aspx
/*
When wParam is DBT_DEVICEARRIVAL lParam will be a pointer to a structure identifying the
device inserted. The structure consists of an event-independent header,followed by event
-dependent members that describe the device. To use this structure, treat the structure
as a DEV_BROADCAST_HDR structure, then check its dbch_devicetype member to determine the
device type.
*/
dbch_devicetype := NumGet(lParam+4) ; dbch_devicetype is member 2 of DEV_BROADCAST_HDR
If ( wParam = DBT_DEVICEARRIVAL AND dbch_devicetype = DBT_DEVTYP_VOLUME )
{
; Confirmed lParam is a pointer to DEV_BROADCAST_VOLUME and should retrieve Member 4
; which is dbcv_unitmask
dbcv_unitmask := NumGet(lParam+12 )
; The logical unit mask identifying one or more logical units. Each bit in the mask corres
; ponds to one logical drive.Bit 0 represents drive A, Bit 1 represents drive B, and so on
Loop 32 ; Scan Bits from LSB to MSB
If ( ( dbcv_unitmask >> (A_Index-1) & 1) = 1 ) ; If Bit is "ON"
{
Drv := Chr(64+A_Index) ; Set Drive letter
Break
}
SetTimer, DriveData, -1
}
Return TRUE
}
DriveData:
DriveGet, Type , Type , %Drv%:
DriveGet, Label , Label , %Drv%:
DriveGet, Serial, Serial, %Drv%:
MsgBox, 262144, Media Insert Notification [ Drive %Drv%: ]
, Type:`t%Type%`nLabel:`t%Label%`nSerial:`t%Serial%
Return |
The above now works in all the 3 OS' flawlessly but still I am a bit uncomfortable
Am I missing something ? 
Last edited by SKAN on Fri Nov 09, 2007 12:51 am; edited 1 time in total |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4015 Location: Pittsburgh
|
Posted: Tue Jun 19, 2007 8:32 pm Post subject: |
|
|
Finding the least- and most significant set (and clear) bit is such a common task, that there are runtime library functions for it, at least in WinNT, 2K and later: | Code: | MsgBox % DllCall("ntdll\RtlFindLeastSignificantBit",Int64,100) ; LS bit is at pos 2
MsgBox % DllCall("ntdll\RtlFindMostSignificantBit", Int64,100) ; MS bit is at pos 6 |
|
|
| Back to top |
|
 |
SKAN
Joined: 26 Dec 2005 Posts: 5882
|
Posted: Sat Sep 01, 2007 2:16 am Post subject: |
|
|
Thank you Sir! I am writing XP specific code and this info was useful!  |
|
| Back to top |
|
 |
|