Don't click here unless you want to be banned.

LSL Wiki : Bitwise

HomePage :: PageIndex :: RecentChanges :: RecentlyCommented :: UserSettings :: You are ec2-204-236-235-245.compute-1.amazonaws.com

Bitwise Operators


Bitwise operators are used to manipulate integers that represent bitfields. Click on an operator below to scroll directly to the position of its description.

Operator Name Usage Reference
& AND integer & integer = integer
| OR integer | integer = integer
~ NOT ~integer = integer
^ XOR integer ^ integer = integer
>> Right-shift integer >> number of bits = integer
<< Left-shift integer << number of bits = integer


AND


The AND operation compares each bit in two integers; if both bits are set to "1", then the final result will be "1", otherwise it will be "0". This is done "per-bit", or "bitwise".

Truth Table:
AND 1 0
1 1 0
0 0 0

Usage:
// A bitfield whose [[binary]] representation is: 00000000000000000000000000001010
integer a = 10;

// Another bitfield whose binary representation is: 00000000000000000000000000011001
integer b = 25;

// The next line translates to "store the result of AND'ing a and b together" in the variable a_AND_b.
// Its binary representation is 00000000000000000000000000001000, or 8.
integer a_AND_b = a & b;
The reason a_AND_b is 8, is that the & operator compared the two bitfields passed to it, a and b, and turned on only the bits that were both 1. The operation is written out like this:
a      00000000000000000000000000001010 // As decimal = 10
b      00000000000000000000000000011001 // As decimal = 25
-----------------------------------------------------------------
a & b  00000000000000000000000000001000 // As decimal = 8
& is commonly used with the control event, when finding out which buttons were pressed by the user.
For example, if the user is holding down the up arrow:
control(key controller, integer levels, integer edges) {
    // If user is holding down up arrow:
    if ((levels & CONTROL_FWD) == CONTROL_FWD) {

            // Do stuff...
    }
}
Commonly, many buttons are held down at the same time. Using bitfields then makes sense because each button can be represented by a bit in the levels bitfield.
control(key controller, integer levels, integer edges) {
    // If user is holding down up arrow:
    if ((levels & CONTROL_FWD) == CONTROL_FWD) {
        // The above translates to: "If the CONTROL_FWD bit is 1 in the levels bitfield"
    }

    // If user is holding down down arrow:
    if ((levels & CONTROL_BACK) == CONTROL_BACK) {
        // The above translates to: "If the CONTROL_BACK bit is 1 in the levels bitfield"
    }
}
Here's the operation (levels & CONTROL_BACK), when the user is holding down both the up and down arrows, written out longwise:
levels                00000000000000000000000000000011 // As decimal = 3
CONTROL_BACK          00000000000000000000000000000010 // As decimal = 2
-------------------------------------------------------------------------------
levels & CONTROL_BACK 00000000000000000000000000000010 // As decimal = 2
Back to top


OR


OR places a 1 in the bitfield if either bitfields passed to it have a 1 in that position. If neither has a 1, it places a 0 in that position.

Truth Table:
OR 1 0
1 1 1
0 1 0

Usage:
// A bitfield whose binary representation is: 00000000000000000000000000001010
integer a = 10;

// Another bitfield whose binary representation is: 00000000000000000000000000011001
integer b = 25;

// The next line translates to "store the result of OR'ing a and b together" in the variable a_OR_b.
// Its binary representation is 00000000000000000000000000011011, or 27.
integer a_OR_b = a | b;
Here's that operation written out longwise:
a      00000000000000000000000000001010 // As decimal = 10
b      00000000000000000000000000011001 // As decimal = 25
--------------------------------------------------------------------
a | b  00000000000000000000000000011011 // As decimal = 27
OR is useful in combining two bits, a good use of this would be executing some statements if the user has both the up arrow and down arrow pressed in the control event.
control(key controller, integer levels, integer edges) {
    // If user is pressing both the up arrow and down arrow:
    if ((levels & (CONTROL_FWD | CONTROL_BACK)) == (CONTROL_FWD | CONTROL_BACK)) {
        // The above statement translates to: "If levels has both the CONTROL_FWD and CONTROL_BACK bits set to 1"
    }
}

Written out in longhand, the conditional statement looks like this:
The ORing operation, to get a bitfield with both CONTROL_FWD and CONTROL_BACK set to 1.

CONTROL_FWD                  00000000000000000000000000000001 // As decimal = 1
CONTROL_BACK                 00000000000000000000000000000010 // As decimal = 2
-----------------------------------------------------------------------------------------
(CONTROL_FWD | CONTROL_BACK) 00000000000000000000000000000011 // As decimal = 3

The ANDing operation, to see if the both CONTROL_FWD and CONTROL_BACK are set to 1 in levels.
In this case, levels is a bitfield in which CONTROL_FWD, CONTROL_BACK and CONTROL_UP are set to 1.

(CONTROL_FWD | CONTROL_BACK)          00000000000000000000000000000011 // As decimal = 3
levels                                00000000000000000000000000010011 // As decimal = 19
-----------------------------------------------------------------------------------------
levels & (CONTROL_FWD | CONTROL_BACK) 00000000000000000000000000000011 // As decimal = 3

Back to top

NOT


NOT is unlike the other bitwise operators in that it does not perform an operation on two bitfields. It only performs an operation on one. What it does is reverse the bitfield; if a bit was previously 0, it is changed to 1, and vice versa.
Truth Table:
NOT
1 0
0 1

Usage:
// A bitfield whose binary representation is: 00000000000000000000000000001010
integer a = 10;

// The next line translates to "store the result of NOTing a" in the variable NOT_a.
// Its binary representation is 11111111111111111111111111110101, or -11.
integer NOT_a = ~a;
Here is that operation written out longwise:

a    00000000000000000000000000001010 // As decimal = 10
-----------------------------------------------------------------------
~a   11111111111111111111111111110101 // As decimal = -11

NOT is commonly used to set bits to 0 in bitfields. To do this, a bit is NOTed to get ~bit. The bitfield is then ANDed with the ~bit.
For example, lets say you wanted to turn off 00000000000000000000000000000010 (2 in decimal) in the bitfield 00000000000000000000000000011010 (26 in decimal).
First you'd get ~00000000000000000000000000000010, which is 11111111111111111111111111111101 (-3 in decimal) then you'd AND ~2 and 26. Here is this in code:

integer bitfield = 26; 
integer bit = 2;
bitfield = bitfield & ~bit;

Here are the operations written out longwise:
2       00000000000000000000000000000010
-----------------------------------------------------------------------
~2      11111111111111111111111111111101 // As decimal = -3


26      00000000000000000000000000011010
~2      11111111111111111111111111111101
-----------------------------------------------------------------------
26 & ~2 00000000000000000000000000011000 // As decimal = 24

Back to top


XOR


Short for "eXclusive OR", XOR sets a bit to 1 in the resulting bitfield if, and only if, a bit in that position is set in one of the bitfields passed to it, and a bit in that position is not set in the other bitfield passed to it. It only sets a bit if the bits of the bitfields passed to it arent the same.
Truth Table:
XOR 1 0
1 0 1
0 1 0

Usage:
// A bitfield whose binary representation is: 00000000000000000000000000001010
integer a = 10;

// Another bitfield whose binary representation is: 00000000000000000000000000011001
integer b = 25;

// The next line translates to "store the result of XORing a and b together" in the variable a_XOR_b.
// Its binary representation is 00000000000000000000000000010011, or 19.
integer a_XOR_b = a ^ b;
Here's the same operation written out longwise:
a     00000000000000000000000000001010 // As decimal = 10
b     00000000000000000000000000011001 // As decimal = 25
-----------------------------------------------------------------------
a ^ b 00000000000000000000000000010011 // As decimal = 19

XOR is useful when you want to execute code when one condition is true, and one is not. For example, if the up arrow is pressed when the right arrow is not or vice versa.

control(key controller, integer levels, integer edges) {
    // If user is pressing CONTROL_FWD but not CONTROL_RIGHT, or vice versa.
    if (((levels & CONTROL_FWD) == CONTROL_FWD) ^ ((levels & CONTROL_RIGHT) == CONTROL_RIGHT)) {
        // The above translates to: "If CONTROL_FWD is being pressed and CONTROL_RIGHT is 
        // not being presed, or CONTROL_FWD is not being pressed and CONTROL_RIGHT is being pressed.
    }
}

When doing bitwise math, XOR works as follows:
4 ^ 2 = 6 in decimal
4 = 100 in binary
2 =  10 in binary
So when we compare them starting at the 1s place, they are both false, so it is a 0. Then at the 2s place, in the 2 it is true and in the 4 it is false, so it return true. Then in the 4s place in the 4 it is true and false in the 2, so it returns true.
100
010
------
110
another example is say
6 ^ 2 = 4 in decimal
6 = 110 in binary
2 =  10 in binary
So when we compare them starting at the 1s place, they are both false, so it is a 0. Then at the 2s place, if they are both true, and since it is the exclusive or, it returns false. Then in the 4s place in the 6 it is true and false in the 2, so it returns true.
110
010
100

A last use for XOR is switching variables. Usually, when you switch variables, you use a temporary variable to hold one place, but with XOT, this temporary variable can be avoided. An example:

Traditional Method:
x = 5
y = 7

w = x
x = y
y = w

x = 7
y = 5

The variable w takes up space and can be avoided with XOR.

XOT method:

x = 5
y = 7

x = x ^ y
y = x ^ y
x = x ^ y

x = 7
y = 5

Binary:

    0101
    0111
    ------
x = 0010 = 2


    0010
    0111
    ------
y = 0101 = 5


    0010
    0101
    ------
x = 0111 = 7

Therefore, x and y are switched without a temporary variable.

Last but not least you can use XOR to turn off bits in a field, without needing to AND a bitfield with a ~bit as described above:

XOR instead of bitfield AND ~bit:

Lets say, we want to turn of two bits (lets say the 2nd and the 5th) in the field 00000000000000000000000000011010
To do so, we XOR that with a field where exactly the bits are set, which we want to turn off:

00000000000000000000000000011010 
00000000000000000000000000010010
------------------------------------- XOR
00000000000000000000000000001000

That can be usefull to switch on/off alot of true/false settings (flags) in only one global variable, what can speed up a script in some tight cases.

Back to top


Right-Shift


This shifts all the bits in an integer to the right by the number of bits specified. Bits shifted out on the right (least significant) end of the word are discarded. Bits shifted in on the left (most significant) end of the word are copies of the word's original most significant bit (sign bit).

Apart from using it for shifting values around in bitfields, this is useful for doing very fast integer divison of positive number by powers of 2. Each bit shifted to the right equals a division by 2. Note that this will always round towards negative infinity; for positive numbers this is the same as rounding down towards zero, but has odd effects on negative numbers. For example, 99>>4 = 6, but (-99)>>4 = -7. Note in particular that (-1)>>1 = -1.

Useage:
// shifts the integer 523 to the right by 2 bits, storing the result in foo
integer foo = 523 >> 2;

Longwise:
a       00000000000000000000001000001011 // decimal 523
----------------------------------------------------------
a >> 2  00000000000000000000000010000010 // decimal 130

Back to top


Left-Shift


This shifts all the bits in an integer to the left by the number of bits specified. Bits will be cut off on the left (most significant) and filled up with 0 on the right.

Apart from using it for shifting values around in bitfields, this is useful for doing very fast integer multiplication by powers of 2. Each bit shifted to the left equals a multiplication by 2. Note that on an overflow on the left, bits will either fall into the value's sign bit (the most significant bit in the 32-bit word) or simply be cut off; in either case, the result will probably not be what you expected.

Useage:
// shifts the integer 523 to the left by 2 bits, storing the result in foo
integer foo = 523 << 2;

Longwise:
a       00000000000000000000001000001011 // decimal 523
----------------------------------------------------------
a << 2  00000000000000000000100000101100 // decimal 2092


Back to top

Operators | Unary | Binary | Bitwise | Boolean | Equality | Assignment
There are 5 comments on this page. [Display comments/form]