Structure: Bitwise Operators Flashcards

1
Q

The bitwise operators perform their calculations at the bit level of variables. In C++ is a single ampersand, &, used between two other integer expressions. It operates on each bit position of the surrounding expressions independently, according to this rule: if both input bits are 1, the resulting output is 1, otherwise the output is 0.

A

Bitwise And (&)

Another way of expressing what was on the front of the card is:

0 0 1 1 operand1

0 1 0 1 operand2

0 0 0 1 (operand1 & operand2) - returned result

In Arduino, the type int is a 16-bit value, so using & between two int expressions causes 16 simultaneous AND operations to occur. In a code fragment like:

int a = 92; // in binary: 0000000001011100

int b = 101; // in binary: 0000000001100101

int c = a & b; // result: 0000000001000100, or 68 in decimal.

Each of the 16 bits in a and b are processed by using the bitwise AND, and all 16 resulting bits are stored in c, resulting in the value 01000100 in binary, which is 68 in decimal.

One of the most common uses of bitwise AND is to select a particular bit (or bits) from an integer value, often called masking. See below for an example

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

Similar to bitwise &, except will be counted as true when either or is chosen.

A

Bitwise Or (|)

The bitwise OR operator in C++ is the vertical bar symbol, |. Like the & operator, | operates independently each bit in its two surrounding integer expressions, but what it does is different (of course). The bitwise OR of two bits is 1 if either or both of the input bits is 1, otherwise it is 0. In other words:

0 0 1 1 operand1

0 1 0 1 operand2

0 1 1 1 (operand1 | operand2) - returned result

Here is an example of the bitwise OR used in a snippet of C++ code:

int a = 92; // in binary: 0000000001011100

int b = 101; // in binary: 0000000001100101

int c = a | b; // result: 0000000001111101, or 125 in decimal.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

There is a somewhat unusual operator in C++ called bitwise EXCLUSIVE OR, also known as bitwise XOR. (In English this is usually pronounced “eks-or”.). This operator is very similar to the bitwise OR operator |, only it evaluates to 0 for a given bit position when both of the input bits for that position are 1:

A

0 0 1 1 operand1

0 1 0 1 operand2

0 1 1 0 (operand1 ^ operand2) - returned result

Another way to look at bitwise XOR is that each bit in the result is a 1 if the input bits are different, or 0 if they are the same.

Here is a simple code example:

int x = 12; // binary: 1100

int y = 10; // binary: 1010

int z = x ^ y; // binary: 0110, or decimal 6

The ^ operator is often used to toggle (i.e. change from 0 to 1, or 1 to 0) some of the bits in an integer expression. In a bitwise OR operation if there is a 1 in the mask bit, that bit is inverted; if there is a 0, the bit is not inverted and stays the same. Below is a program to blink digital pin 5.

// Blink_Pin_5

// demo for Exclusive OR

void setup()

{

DDRD = DDRD | B00100000; // set digital pin five as OUTPUT

Serial.begin(9600);

}

void loop()

{

PORTD = PORTD ^ B00100000; // invert bit 5 (digital pin 5), leave others untouched

delay(100);

}

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

Unlike & and |, the bitwise operator is applied to a single operand to its right. The operator changes each bit to its opposite: 0 becomes 1, and 1 becomes 0.

A

0 1 operand1

1 0 ~ operand1

int a = 103; // binary: 0000000001100111

int b = ~a; // binary: 1111111110011000 = -104

You might be surprised to see a negative number like -104 as the result of this operation. This is because the highest bit in an int variable is the so-called sign bit. If the highest bit is 1, the number is interpreted as negative. This encoding of positive and negative numbers is referred to as two’s complement.

As an aside, it is interesting to note that for any integer x, ~x is the same as -x-1

At times, the sign bit in a signed integer expression can cause some unwanted surprises

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

There are two bit shift operators in C++: the left shift operator << and the right shift operator >>. These operators cause the bits in the left operand to be shifted left or right by the number of positions specified by the right operand.

A

the left shift operator <<

the right shift operator >>

Syntax

variable << number_of_bits

variable >> number_of_bits

Example

int a = 5; // binary: 0000000000000101

int b = a << 3; // binary: 0000000000101000, or 40 in decimal

int c = b >> 3; // binary: 0000000000000101, or back to 5 like we started with

When you shift a value x by y bits (x << y), the leftmost y bits in x are lost, literally shifted out of existence:

int a = 5; // binary: 0000000000000101

int b = a << 14; // binary: 0100000000000000 - the first 1 in 101 was discarded

If you are certain that none of the ones in a value are being shifted into oblivion, a simple way to think of the left-shift operator is that it multiplies the left operand by 2 raised to the right operand power. For example, to generate powers of 2, the following expressions can be employed:

1 << 0 == 1

1 << 1 == 2

1 << 2 == 4

1 << 3 == 8

1 << 8 == 256

1 << 9 == 512

1 << 10 == 1024

When you shift x right by y bits (x >> y), and the highest bit in x is a 1, the behavior depends on the exact data type of x. If x is of type int, the highest bit is the sign bit, determining whether x is negative or not, as we have discussed above. In that case, the sign bit is copied into lower bits, for esoteric historical reasons:

int x = -16; // binary: 1111111111110000

int y = x >> 3; // binary: 1111111111111110

This behavior, called sign extension, is often not the behavior you want. Instead, you may wish zeros to be shifted in from the left. It turns out that the right shift rules are different for unsigned int expressions, so you can use a typecast to suppress ones being copied from the left:

int x = -16; // binary: 1111111111110000

int y = (unsigned int)x >> 3; // binary: 0001111111111110

If you are careful to avoid sign extension, you can use the right-shift operator >> as a way to divide by powers of 2. For example:

int x = 1000;

int y = x >> 3; // integer division of 1000 by 8, causing y = 125.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly