Sign in to follow this  
Followers 0
crashdemons

More bitwise functions

5 posts in this topic

#1 ·  Posted (edited)

I checked with Search but I didn't see anything too comprehensive. **

These may not be useful to anyone, but I needed them. :)

I needed some simple functions to:

  • Fill out some operations that weren't provided
  • Be able to read out numbers as bit strings (binary)
  • Convert bit strings to numbers
  • Be able to get/set specific bits in a value.
  • Do some other obscure stuff with bits
Note:

Be warned though, it seemed easiest to use BitShift and BitAnd to gain access to the Least Significant Bit - thus, many of these functions work as if the number was Little-Endian.

This shouldn't be a major issue except causing confusion with inbuilt Bitwise operations (which I assume use Big-Endian) and using a reversed bit order for strings.

To help combat the confusion, I included a parameter for Big-Endian on a couple functions.

If you're thinking in terms of Big-Endian, this is all Right-to-Left.

If you let me know about existing functions for something here, if there are, I will take a look.

Code: (Includes function descriptions and a table of example outputs)

;More Bitwise functions!
;AUTHOR: Crash Daemonicus

;INTRODUCTORY NOTES
;    Except where noted, all functions here are little-endian and
;        consider the Least-Significant-Bit to be the first/leftmost one. (and the zeroth bit index)
;        thus, bit reading starts with the Least Significant as index 0 and continues to get More Significant as the bit index increases.
;       WARNING: BitShift/etc appear to use Big-Endian.
;    All "iBit" parameters are a 0-based bit index (little-endian)
;        also, all "iLen" parameters are bit length values.
;        extending past this, the phrase "subrange" refers to an amount of bits from a position, defined by a Start and End position, or alternatively Start and Length values.
;    To get the same output as Windows Calc while using BitStr(...) you must set the BigEndian parameter to True or use BitReverse first.
;       Windows Calc displays Big Endian bit strings that start with the first bit set to 1 as the Most-Significant-Bit and get Less-significant moving rightward.

;FUNCTIONS:
;    BitStr - Returns a bit string with the a specified data size and endianness.
;    StrBit - Returns the value of a bit string with a specified data size and endianness.
;    BitGet - Returns the value of a specific bit index in an input number.
;    BitSet - Returns the input number with the bit at a specified index set to a specified value.
;    BitLen - Returns the minimum number of bits required to hold the input number.
;   -------------------------------------------------------------------------------------------------
;    BitNAnd - Returns a BitNot'd BitAnd result of two input numbers.
;    BitNOr  - Returns a BitNot'd BitOr result of two input numbers.  Checks if both bits are 0.
;    BitXNOr - Returns a BitNot'd BitXOr result of two input numbers. Checks bit equivalence to each oter
;    BitImp - Returns a number with a bit set to 1 when first input value implies the second - or rather, a BitOR result of Not(A) with B.
;   -------------------------------------------------------------------------------------------------
;    BitLess - Returns a number with a bit set to 1 when the corresponding bit in the first input number is less than the second. (eg: 0,1 -> 1)
;    BitTrim - Returns the input number with a specified number of bits at the beginning set to 0.
;    BitMid - Returns a number representing a specific subrange of bits from the input value.
;    BitReverse - Returns the input number with a specified subrange of bits in reverse order.
;    BitIsolate - Returns the input number with all bits, except the specified subrange of bits, set to 0.
;    BitAltNot - Returns the input number with NOT applied to alternating bits.
;    BitChanged - Returns a number with a bit set to 1 where the corresponding bit in the input value differs from its preceding bit.

;EXAMPLES:
;---------------------------------------------------------------
; Function Used    | Input Value 1 (a)  | Input Value 2 (b)
;---------------------------------------------------------------
;                  |         170         |        240
;---------------------------------------------------------------
; BitStr(_, 16)    | 0101010100000000    | 0000111100000000
; BitStr(_, 8)     | 01010101            | 00001111
; BitStr(_, 4)     | 0101                | 0000
; BitGet(_, 1)     |  1                  |  0
; BitSet(_, 3,1)   | 01010101            | 00011111
; BitSet(_, 3,0)   | 01000101            | 00001111
; BitNAnd(a,b)     | 11111010            |
; BitNOr(a,b)      | 10100000            |
; BitXNor(a,b)     | 10100101            |
; BitImp(a,b)      | 10101111            |
; BitImp(b,a)      | 11110101            |
; BitLess(a,b)     | 00001010            |
; BitLess(b,a)     | 01010000            |
; BitTrim(_, 5)    | 00000101            | 00000111
; BitMid(_, 2,4)   |   0101              |   0001
; BitReverse(_,0,8)| 10101010            | 11110000
; BitReverse(_,2,4)| 01101001            | 00110011
; BitIsolate(_,2,4)| 00010100            | 00001100
; BitAltNot(_)     | 00000000            | 01011010
; BitChanged(_)    | 11111111            | 10001000
;---------------------------------------------------------------
; * Bit strings in this table are mostly 8-bit Little-Endian (reverse them to make any sense)
;    Remember: The leftmost bit displayed here is the LEAST-SIGNIFICANT (smallest value) and the rightmost in a Big-Endian form.
;---------------------------------------------------------------

Func BitStr($n,$iLen=32,$BigEndian=False); in all likelyhood, you'll probably prefer *viewing* BigEndian bit strings.
    Local $s="",$start=0,$end=($iLen-1),$step=1
    If $BigEndian Then
        $start=$end
        $end=0
        $step=-1
    EndIf
    For $i=$start To $end Step $step
        $s&=BitGet($n,$i)
    Next
    Return $s
EndFunc
Func StrBit($s,$iLen=32,$BigEndian=False); in all likelyhood, you'll probably prefer *viewing* BigEndian bit strings.
    Local $start=1, $end=StringLen($s), $step=1, $t=0, $p=0, $c
    If $end>$iLen Then $end=$iLen
    If $BigEndian Then
        $start=$end
        $end=1
        $step=-1
    EndIf
    For $i=$start To $end Step $step
        $c=StringMid($s,$i,1)
        If $c='b' Or $c=' ' Then ContinueLoop
        $t=BitSet($t,$p,Int($c))
        $p+=1
    Next
    Return $t
EndFunc

Func BitGet($n,$iBit=0)
    ;Gets the bit value at a specific 0-based bit index.  (0=LSB)
    ; if n is input as 14 (1110b Big Endian) and iBit is input as 0 - 3,
    ; this would output 0, 1, 1, and 1  (Little Endian)
    Return BitAnd(BitShift($n,$iBit),1)
EndFunc
Func BitSet($n,$iBit=0,$Value=0)
    ;Sets the bit value at a specific 0-based bit index
    If $Value<>0 Then; we assume this is 1
        Return BitOr($n,BitShift(1,-$iBit))
    Else
        Return BitAnd($n,BitNot(BitShift(1,-$iBit)))
    EndIf
EndFunc
Func BitLen($n,$iMaxLen=32)
    If $n<0 Then Return $iMaxLen
    Local $i=0
    While $n<>0
        $n=BitShift($n,1)
        $i+=1
    WEnd
    Return $i
EndFunc




; Bit logic - check these (are we sure the parameters aren't BitNot()'d instead??)
Func BitNAnd($n,$n2); could be called "BitNotBoth"
    Return BitNot(BitAnd($n,$n2))
EndFunc
Func BitNOr($n,$n2); could also be called "BitIsZero" or "BitNeither", since it's only 1 when both compared bits are 0
    Return BitNot(BitOR($n,$n2))
EndFunc
Func BitXNOr($n,$n2); could be called "BitEqual", since its only 1 when both bits match. (thus XOR is "BitNotEqual")
    Return BitNot(BitXOR($n,$n2)); check this
EndFunc
Func BitImp($n,$n2)
    ; A implies B
    ;(Not A) Or (B)
    ;http://en.wikipedia.org/wiki/Material_conditional
    ;Note:  for Converse Implication just use BitImp($n2,$n)
    ;Note2: same as a<=b (a [less than or equal to] b, which was formerly BitLessEqual. )
    Return BitOR(BitNot($n),$n2)
EndFunc


;more bit logic - order matters!
Func BitLess($n,$n2)
    Local $t=0
    For $i=0 To 31
        If BitGet($n,$i)<BitGet($n2,$i) Then $t=BitSet($t,$i,1)
    Next
    Return $t
EndFunc


;editing the values as if bits were characters in a string
Func BitTrim($n,$iLen=1);sets a number of bits starting at the beginning(LSB) to 0
    Return BitShift(BitShift($n,$iLen),-$iLen)
EndFunc
Func BitMid($n,$iBitStart,$iLen)
    ;retrieves a range of bits
    Return BitAND(BitShift($n,$iBitStart),BitNot(BitTrim(BitNot(0),$iLen)))
EndFunc
Func BitReverse($n,$iBitStart=0,$iLen=32)
    ;Returns a number with the selected subrange of bits reversed.
    Local $iBitEnd=$iBitStart+($iLen-1)
    Local $t=$n
    For $i=$iBitStart To $iBitEnd
        ;ConsoleWrite($i&':'&($iBitEnd-($i-$iBitStart))&' = '&BitGet($n,$iBitEnd-$i)&@CRLF)
        $t=BitSet($t,$i,BitGet($n,($iBitEnd-($i-$iBitStart))))
    Next
    Return $t
EndFunc

; really strange functions - this is like BitTrim, but for both sides of a selection
Func BitIsolate($n,$iBitStart,$iLen)
    ; surrounds a subrange of bits with 0's, not changing the bits' position.
    Return BitAND($n,BitXor(BitTrim(BitNot(0),$iBitStart),BitTrim(BitNot(0),$iBitStart+$iLen)))
EndFunc

Func BitAltNot($n,$Evens=False)
    ; ? might be good for obfuscating numbers.
    ; applies NOT to alternating bits (eg:  000000000000 -> 1010101010...)
    ; If you apply this twice with the same parameters, the number reverts to the original value.
    Local $x=1
    If $Evens Then $x+=1
    For $i=0 To 31
        If Mod($i+$x,2)=0 Then
            If BitGet($n,$i)=1 Then
                $n=BitSet($n,$i,0)
            Else
                $n=BitSet($n,$i,1)
            Endif
        EndIf
    Next
    Return $n
EndFunc
Func BitChanged($n)
    ; not sure what this is good for
    ;- returns a number with positions where the bit differed with the previous (bit 0 is always marked)
    Local $t=0,$b=-1,$bt
    For $i=0 To 31
        $bt=BitGet($n,$i)
        If $bt<>$b Then
            $b=$bt
            $t=BitSet($t,$i,1)
        Endif
    Next
    Return $t
EndFunc

** (Frankly, I think more excerpt text needs to be included in Search results for context - but that's off-topic.)

Edited by crashdemons

My Projects - WindowDarken (Darken except the active window) Yahsmosis Chat Client (Discontinued) StarShooter Game (Red alert! All hands to battlestations!) YMSG Protocol Support (Discontinued) Circular Keyboard and OSK example. (aka Iris KB) Target Screensaver Drive Toolbar Thingy Rollup Pro (Minimize-to-Titlebar & More!) 2D Launcher physics example Ascii Screenshot AutoIt3 Quine Example ("Is a Quine" is a Quine.) USB Lock (Another system keydrive - with a toast.)

Share this post


Link to post
Share on other sites



Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

crashdemons,

Interesting code tidbits.. I think there's a bunch of people that have already done Binary-base conversion or bit-operations. I myself did two base-conversions (in my sig), but I went for the full 64-bits (not supported yet by Bit*() functions unfortunately), and also created Assembly language versions using my _RemoteCodeExecution UDF... but hey, everyone gets to learn even if they are reinventing (parts of) the same wheel.

Oh, and btw - the Bit*() functions work on numbers the same way everything else in x86 architecture works - Little Endian. It makes more sense to output strings in Big Endian format though.

*edit:typo

Edited by Ascend4nt

Share this post


Link to post
Share on other sites

#4 ·  Posted (edited)

Oh, and btw - the Bit*() functions work on numbers the same way everything else in x86 architecture works - Little Endian.

Um yeah, except if you BitShift right a number by one bit you lose the Least Significant Bit.

$n=BitShift(BitShift(3,1),-1); should now be 2 if we lost the LSB
 MsgBox(0,"",$n)

So, if we assume the LSB is on the right and the MSB is on the left

- and if we read left to right - then the Most Significant Bit is being read first - making this Big Endian, no?

Also, if that weren't enough, the binary text in the examples for the help file reflect Big Endian values.

Although, perhaps you meant Little Endian is ultimately used at some level, but it doesn't seem to be made apparent in either form or feature here.

------------------------------------------

However, I don't think this is a dead-end topic because there are more complicated Bit operations that could be added to this - I just can't think of any at the moment.

And while I know that doing these in AutoIt has a sacrifice to speed, but what else are you going to do to get the nth bit? :)

@Yashied - why in the world did you need a for loop in _SetBit and _GetBit ?

perhaps not relying on loops might have increased your efficiency.

Some of my functions loop, but BitGet and BitSet do not (single bits), also - BitMid (which can be used to get a range of bits) does not loop either.

Have a look.

As for the ones that do use loops, I'd love to remove their loops, if it is possible.

Edited by crashdemons

My Projects - WindowDarken (Darken except the active window) Yahsmosis Chat Client (Discontinued) StarShooter Game (Red alert! All hands to battlestations!) YMSG Protocol Support (Discontinued) Circular Keyboard and OSK example. (aka Iris KB) Target Screensaver Drive Toolbar Thingy Rollup Pro (Minimize-to-Titlebar & More!) 2D Launcher physics example Ascii Screenshot AutoIt3 Quine Example ("Is a Quine" is a Quine.) USB Lock (Another system keydrive - with a toast.)

Share this post


Link to post
Share on other sites

Um yeah, except if you BitShift right a number by one bit you lose the Least Significant Bit.

$n=BitShift(BitShift(3,1),-1); should now be 2 if we lost the LSB
 MsgBox(0,"",$n)

So, if we assume the LSB is on the right and the MSB is on the left

- and if we read left to right - then the Most Significant Bit is being read first - making this Big Endian, no?

Also, if that weren't enough, the binary text in the examples for the help file reflect Big Endian values.

crashdemons,

Okay, I see where the confusion is. BitShift left/right is confusing in that the terminology used, even at the Assembly level, talks about 'right' being towards the least significant bit, and 'left' towards the most significant bit. There's more bit movement operations that refer to shifting/scanning/rotating bits left or right, but you have to think of the number as a 'whole' at that point. On a 'byte' level, it would be correct, because individual bytes are stored in 'Big Endian bit form'... its just when you go to multi-byte operations (16-bit, 32-bit, 64-bit etc), that the 'Little-Endianess' comes into play, because Endianess really refers to bytes, not bits.

So hex # AB CD (2 bytes) is stored as CD AB in memory, not DC BA, as would a 32-bit # of 09 AB CD EF (stored as EF CD AB 09).

You can see this for yourself by doing this:

MsgBox(0,"",Binary(0x09ABCDEF))

Binary takes the number and breaks it down into a byte-by-byte operation. That's the best way to see how Endianess works on the Intel platform..

Does that help any?

Share this post


Link to post
Share on other sites

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 account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0