GregN Posted December 18, 2009 Posted December 18, 2009 Hi everyone, I'm trying to make a simple app that can look up a bit within a 32bin HEX value. Can someone provide some advice or examples? Example1; Hex value: 3F8A9556 I want to look up bit 31 (it should return 0) Example2 Hex value: 1D12AAA I want to look up bits 27-30 (it should return 0000 or just 0) Thanks guys! Greg
AdmiralAlkex Posted December 18, 2009 Posted December 18, 2009 BinaryMid() ? .Some of my scripts: ShiftER, Codec-Control, Resolution switcher for HTC ShiftSome of my UDFs: SDL UDF, SetDefaultDllDirectories, Converting GDI+ Bitmap/Image to SDL Surface
danielkza Posted December 18, 2009 Posted December 18, 2009 This is how I'd do it: basically, you need to do two things. 1-) Shift your value to the right enough times as to position your first wanted bit in index 0 2-) Create and bitAND a mask that unsets the bits you do not want. It is a bit tricky because AutoIT doesn't have an unsigned-right-shift function. But you can get around that with a bit of thinking. PS: I was bored and ended up doing it for ya. Here it is, with nice comments if anybody wants them. I tested it a bit and it seems to work alright, but please check it yourself as well. expandcollapse popupFunc _BitRange($v, $start, $end=-1) ; We only work for integers, sorry If Not IsInt($v) Then Return SetError(1, 0, 0) ; Check for a valid range If $start < 0 Or $start > 31 Then Return SetError(2, 0, 0) EndIf ; Default to retrieving a single bit If $end < 0 Then $end = $start ; Another range check ElseIf $end < $start Then Return SetError(3, 0, 0) EndIf Local $mask, $range=$end-$start ; First, we check if the most significant (sign) bit is of any importance. If $end = 31 Then ; If it is, we first handle the special case of retrieving all the bits. If $start = 0 Then Return $v ; If fewer than 32 bits matter, we can use 1 of the meaningless ones as we wish. ; What allows this is the fact that signed shifts, as in AutoIT, ; set vacant bits to the current value of the sign bit. ; In this case, we can't ignore the most significant bit. ; Because of that, the mask works right-to-left: ; The sign bit is set, and propagates that value to (end-start) bits at its right $mask = BitShift(0x80000000, $range) ; We apply the mask first, then use a rotation to emulate our shift. ; This works because by applying the mask, we assured all non-wanted bits are 0s Return BitRotate(BitAND($v, $mask), -31+$range, "D") EndIf ; Here, we need not care for bit 31 at all. ; Therefore, this mask works left-to-right: the sign bit *cleans* the bits to its right. $mask = BitShift(0x7FFFFFFF, 30-$range) ; Here, we *first* shift the value to the right as much as needed to ; put our first wanted bit at index 0 ; Then, afterwards, we apply our mask, and we're done. Return BitAND(BitShift($v, $start), $mask) EndFunc
danielkza Posted December 18, 2009 Posted December 18, 2009 (edited) BinaryMid() ?bah, reinventing the wheel is much funnier. Edited December 18, 2009 by danielkza
GregN Posted December 18, 2009 Author Posted December 18, 2009 Thanks a lot AdmiralAlkex and danielkza! I appreciate your guys help! I'm kind of a newb here, and have been trying to figure this out. I'm going to try both options right away. Greg
Malkey Posted December 18, 2009 Posted December 18, 2009 I found danielkza and my approach return the same result, although the parameters differ being zero-based and 1-based respectively. BinaryMid() works with bytes as opposed to bits - 32bit(4bytes) The example with BinaryMid() uses the last byte, the last 8 bits. expandcollapse popup; 0x3F8A9556 = 00111111 10001010 10010101 01010110 ConsoleWrite("danielkza " & _BitRange(0x3F8A9556, 23, 31) & @CRLF) ; 0-based ; 0x1D12AAA = 00000001 11010001 00101010 10101010 ConsoleWrite("danielkza " & _BitRange(0x1D12AAA, 27, 30) & @CRLF) ; 0-based ; 0x3F8A9556 = 00111111 10001010 10010101 01010110 ConsoleWrite("Malkey " & _BitValueFromHexMid(0x3F8A9556, 24, 9) & @CRLF) ; 1-based ; 0x1D12AAA = 00000001 11010001 00101010 10101010 ConsoleWrite("Malkey " & _BitValueFromHexMid(0x1D12AAA, 27, 4) & @CRLF) ; 1-based ; 0x3F8A9556 = 00111111 10001010 10010101 01010110 ; 0x0000003F = 00111111 = 63 ConsoleWrite("Fourth Byte " & Dec(Hex(BinaryMid(0x3F8A9556, 4, 1)))) ; 1-based ConsoleWrite(" = danielkza " & _BitRange(0x3F8A9556, 24, 31)) ; 0-based ConsoleWrite(" = Malkey " & _BitValueFromHexMid(0x3F8A9556, 25, 8) & @CRLF) ; 1-based ;For a 32bit number, the right most bit is bit number 0, ; the left most bit is bit number 31. Func _BitRange($v, $start, $end = -1) ; We only work for integers, sorry If Not IsInt($v) Then Return SetError(1, 0, 0) ; Check for a valid range If $start < 0 Or $start > 31 Then Return SetError(2, 0, 0) EndIf ; Default to retrieving a single bit If $end < 0 Then $end = $start ; Another range check ElseIf $end < $start Then Return SetError(3, 0, 0) EndIf Local $mask, $range = $end - $start ; First, we check if the most significant (sign) bit is of any importance. If $end = 31 Then ; If it is, we first handle the special case of retrieving all the bits. If $start = 0 Then Return $v ; If fewer than 32 bits matter, we can use 1 of the meaningless ones as we wish. ; What allows this is the fact that signed shifts, as in AutoIT, ; set vacant bits to the current value of the sign bit. ; In this case, we can't ignore the most significant bit. ; Because of that, the mask works right-to-left: ; The sign bit is set, and propagates that value to (end-start) bits at its right $mask = BitShift(0x80000000, $range) ; We apply the mask first, then use a rotation to emulate our shift. ; This works because by applying the mask, we assured all non-wanted bits are 0s Return BitRotate(BitAND($v, $mask), -31 + $range, "D") EndIf ; Here, we need not care for bit 31 at all. ; Therefore, this mask works left-to-right: the sign bit *cleans* the bits to its right. $mask = BitShift(0x7FFFFFFF, 30 - $range) ; Here, we *first* shift the value to the right as much as needed to ; put our first wanted bit at index 0 ; Then, afterwards, we apply our mask, and we're done. Return BitAND(BitShift($v, $start), $mask) EndFunc ;==>_BitRange ;For a 32bit number, the right most bit is bit number 1, ; the left most bit is bit number 32. Func _BitValueFromHexMid($hex, $iStart, $iCount) Local $b = "", $Output = 0 ;Hex to Binary For $i = 1 To 32 $b = BitAND($hex, 1) & $b $hex = BitShift($hex, 1) Next $Bin = StringMid(StringRegExpReplace($b, "(.{8})", "\1"), 33 - $iCount - $iStart + 1, $iCount) ;Binary to Dec Local $num = StringSplit($Bin, "") Local $Output = $num[$num[0]] For $n = 1 To $num[0] - 1 If $num[$num[0] - $n] = "1" Then $Output += (2 ^ ($n)) Next Return $Output EndFunc ;==>_BitValueFromHexMid
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now