Lect3 Bitwise Operations
Lect3 Bitwise Operations
COMP201
Computer
Systems &
Programming
Lecture #03 –Bits and Bitwise Operators, Floating Point
Aykut Erdem // Koç University // Spring 2023
Recap
• Bits and Bytes
• Hexadecimal
• Integer Representations
• Unsigned Integers
• Signed Integers
• Overflow
• Casting and Combining Types
2
Recap: Unsigned and Signed Integers
15 0 1
14 2
13 3
12 4
11 5
10 6
9 8 7
3
Recap: Overflow in Unsigned Integers
≈+4billion 0
111…111 000…000
111…110 000…001
… …
100…010 011…101
100…001 011…110
100…000 011…111
4
Recap: Overflow in Signed Numbers
-1 0 +1
Negative numbers becoming less negative
111…111 000…000
111…110 000…001
111…101 000…010
… …
Discontinuity
(i.e. increasing)
means overflow
possible here
100…010 011…101
100…001 011…110
100…000 011…111
≈+2billion
≈-2billion 5
Recap: Casting
• What happens at the byte level when we cast between variable types?
The bytes remain the same! This means they may be interpreted
differently depending on the type.
int v = -12345;
unsigned int uv = v;
printf("v = %d, uv = %u\n", v, uv);
11
Comparisons Between Different Types
• Be careful when comparing signed and unsigned integers. C will
implicitly cast the signed argument to unsigned, and then performs the
operation assuming both numbers are non-negative.
Expression Type Evaluation Correct?
0 == 0U Unsigned 1 yes
-1 < 0 Signed 1 yes
-1 < 0U Unsigned 0 No!
2147483647 >
Signed 1 yes
-2147483647 - 1
2147483647U >
Unsigned 0 No!
-2147483647 - 1
2147483647 > Size
Signed 1 No! Type
(Bytes)
Minimum Maximum
(int)2147483648U
-1 > -2 Signed 1 yes int 4 -2147483648 2147483647
unsigned
(unsigned)-1 > -2 Unsigned 1 yes int
4 0 4294967295
12
Comparisons Between Different Types
Which many of the following statements are true? (assume that
variables are set to values that place them in the spots shown)
s3 > u3 - true
u2 > u4 - true
s2 > s4 - false
s1 > s2 - true
u1 > u2 - true
s1 > u3 - true
13
Expanding Bit Representations
• Sometimes, we want to convert between two integers of different sizes
(e.g. short to int, or int to long).
• We might not be able to convert from a bigger data type to a smaller
data type, but we do want to always be able to convert from a smaller
data type to a bigger data type.
• For unsigned values, we can add leading zeros to the representation
(“zero extension”)
• For signed values, we can repeat the sign of the value for new digits
(“sign extension”)
• Note: when doing <, >, <=, >= comparison between different size
types, it will promote to the larger type.
14
Expanding Bit Representation
unsigned short s = 4;
// short is a 16-bit format, so s = 0000 0000 0000 0100b
unsigned int i = s;
// conversion to 32-bit int, so i = 0000 0000 0000 0000 0000 0000 0000 0100b
15
Expanding Bit Representation
short s = 4;
// short is a 16-bit format, so s = 0000 0000 0000 0100b
int i = s;
// conversion to 32-bit int, so i = 0000 0000 0000 0000 0000 0000 0000 0100b
— or —
short s = -4;
// short is a 16-bit format, so s = 1111 1111 1111 1100b
int i = s;
// conversion to 32-bit int, so i = 1111 1111 1111 1111 1111 1111 1111 1100b
16
Truncating Bit Representation
If we want to reduce the bit size of a number, C truncates the representation
and discards the more significant bits.
int x = 53191;
short sx = x;
int y = sx;
What happens here? Let's look at the bits in x (a 32-bit int), 53191:
0000 0000 0000 0000 1100 1111 1100 0111
When we cast x to a short, it only has 16-bits, and C truncates the number:
1100 1111 1100 0111
This is -12345! And when we cast sx back an int, we sign-extend the number.
1111 1111 1111 1111 1100 1111 1100 0111 // still -12345
17
Truncating Bit Representation
If we want to reduce the bit size of a number, C truncates the representation
and discards the more significant bits.
int x = -3;
short sx = x;
int y = sx;
What happens here? Let's look at the bits in x (a 32-bit int), -3:
1111 1111 1111 1111 1111 1111 1111 1101
When we cast x to a short, it only has 16-bits, and C truncates the number:
1111 1111 1111 1101
This is -3! If the number does fit, it will convert fine. y looks like this:
1111 1111 1111 1111 1111 1111 1111 1101 // still -3
18
Truncating Bit Representation
If we want to reduce the bit size of a number, C truncates the representation
and discards the more significant bits.
unsigned int x = 128000;
unsigned short sx = x;
unsigned int y = sx;
What happens here? Let's look at the bits in x (a 32-bit unsigned int), 128000:
0000 0000 0000 0001 1111 0100 0000 0000
When we cast x to a short, it only has 16-bits, and C truncates the number:
1111 0100 0000 0000
This is 62464! Unsigned numbers can lose info too. Here is what y looks like:
0000 0000 0000 0000 1111 0100 0000 0000 // still 62464
19
The sizeof Operator
long sizeof(type);
// Example
long int_size_bytes = sizeof(int); // 4
long short_size_bytes = sizeof(short); // 2
long char_size_bytes = sizeof(char); // 1
sizeof takes a variable type as a parameter and returns the size of that
type, in bytes.
20
Practice: Truncation
What are the values of cx for the passages of code below?
short x = 130; // 0b1000 0010
char cx = x;
21
Practice: Truncation
What are the values of cx for the passages of code below?
short x = 130; // 0b1000 0010
char cx = x; // -126
22
Practice: Truncation
What are the values of cx for the passages of code below?
short x = 390; // 0b1 1000 0110
char cx = x;
23
Practice: Truncation
What are the values of cx for the passages of code below?
short x = 390; // 0b1 1000 0110
char cx = x; // -122
24
In Sum: Basic Rules of Expanding, Truncating
• Expanding (e.g., short int to int)
– Unsigned: zeros added
– Signed: sign extension
– Both yield expected result
26
Number Representations
C Declaration Intel IA32 X86-64
int 4 4
double 8 8
float 4 4
char 1 1
char * 4 8
short 2 2
long 4 8
27
Byte Ordering
• So, how are the bytes within a multi-byte word ordered in memory?
28
Byte Ordering
• So, how are the bytes within a multi-byte word ordered in memory?
• Conventions
– Big Endian: Sun (Oracle SPARC), PPC Mac, Internet
• Least significant byte has highest address
– Little Endian: x86, ARM processors running Android, iOS, and Linux
• Least significant byte has lowest address
29
Byte Ordering Example
• Big Endian: Sun (Oracle SPARC), PPC Mac, Internet
– Least significant byte has highest address
• Little Endian: x86, ARM processors running Android, iOS, and Linux
– Least significant byte has lowest address
• Example:
– Variable x has 4-byte value of 0x01234567
– Address given by &x is 0x100
Big Endian 0x100 0x101 0x102 0x103
01 23 45 67
Little Endian 0x100 0x101 0x102 0x103
67 45 23 01
30
On Holy Wars and a Plea for Peace
Danny Cohen
Information Sciences Institute
Approaches to serialization
The above question arises as a result of the serialization
process performed on messages to allow them to be sent
through communication media. If the unit of communi-
AA.Ai
, i&\ f\R WD9.O e cation is a message, this question has no meaning. If the
units are computer words, one must determine their size
and the order in which they are sent.
Since they are sent virtually at once, there is no need to
determine the order of the elements of these words.
If the unit of transmission is an eight-bit byte, questions
about bytes are meaningful but questions about the order
of the elementary particles that constitute these bytes are
not.
If the units of communication are bits, the atoms
(quarks?) of computation, the only meaningful question
concerns the order in which the bits are sent. Most
modern communication is based on a single stream of in-
formation, the bit-stream. Hence, bits, rather than bytes
or words, are the units of information that are actually
transmitted over channels such as wires and satellites. <'
Facing page: "Audience with the Emperor of Lilliput," Gavarni,
1850's. Courtesy Library of Congress. 0018-9162/81/100040048S00.75 © 1981 IEEE 49 31
The origin of “endian”
“Gulliver finds out that there is a law, proclaimed
by the grandfather of the present ruler, requiring
all citizens of Lilliput to break their eggs only at
the little ends. Of course, all those citizens who
broke their eggs at the big ends were angered by
the proclamation. Civil war broke out between
the Little-Endians and the Big-Endians, resulting
in the Big-Endians taking refuge on a nearby
island, the kingdom of Blefuscu.”
– Danny Cohen, On Holy Wars and A Plea For Peace
(1980)
Illustration by Chris Beatrice
32
Representing Integers Decimal: 15213
Binary: 0011 1011 0110 1101
Hex: 3 B 6 D
33
Aside: ASCII
• ASCII is an encoding from common characters (letters, symbols, etc.)
to bit representations (chars).
– E.g. 'A’ is 0x41
• Neat property: all uppercase letters, and all lowercase letters, are
sequentially represented!
– E.g. 'B’ is 0x42
34
Lecture Plan
• Casting and Combining Types (cont’d.)
• Byte Ordering
• Bitwise Operators
• Bitmasks
• Bit Shift Operators
35
Now that we understand
binary representations, how
can we manipulate them
at the bit level?
Bitwise Operators
• You’re already familiar with many operators in C:
– Arithmetic operators: +, -, *, /, %
– Comparison operators: ==, !=, <, >, <=, >=
– Logical Operators: &&, ||, !
37
And (&)
AND is a binary operator. The AND of 2 bits is 1 if both bits are 1, and 0
otherwise.
output = a & b;
a b output
0 0 0
0 1 0
1 0 0
1 1 1
& with 1 to let a bit through, & with 0 to zero out a bit
38
Or (|)
OR is a binary operator. The OR of 2 bits is 1 if either (or both) bits is 1.
output = a | b;
a b output
0 0 0
0 1 1
1 0 1
1 1 1
| with 1 to turn on a bit, | with 0 to let a bit go through
39
Not (~)
NOT is a unary operator. The NOT of a bit is 1 if the bit is 0, or 1 otherwise.
output = ~a;
a output
0 1
1 0
40
Exclusive Or (^)
Exclusive Or (XOR) is a binary operator. The XOR of 2 bits is 1 if exactly
one of the bits is 1, or 0 otherwise.
output = a ^ b;
a b output
0 0 0
0 1 1
1 0 1
1 1 0
^ with 1 to flip a bit, ^ with 0 to let a bit go through
41
Operators on Multiple Bits
• When these operators are applied to numbers (multiple bits), the operator
is applied to the corresponding bits in each number. For example:
AND OR XOR NOT
42
Operators on Multiple Bits
• When these operators are applied to numbers (multiple bits), the operator
is applied to the corresponding bits in each number. For example:
AND OR XOR NOT
46
Bit Vectors and Sets
• We can use bit vectors (ordered collections of bits) to represent finite sets,
and perform functions such as union, intersection, and complement.
• Example: we can represent current courses taken using a char.
0 0 1 0 0 0 1 1
00
06
32
02
91
01
02
01
P1
P1
P1
P2
P2
P3
P3
P2
M
M
M
O
O
O
C
C
C
47
Bit Vectors and Sets
0 0 1 0 0 0 1 1
00
06
32
02
91
01
02
01
P1
P1
P1
P2
P2
P3
P3
P2
M
M
M
O
O
O
C
C
C
• How do we find the union of two sets of courses taken? Use OR:
00100011
| 01100001
--------
01100011
48
Bit Vectors and Sets
0 0 1 0 0 0 1 1
00
06
32
02
91
01
02
01
P1
P1
P1
P2
P2
P3
P3
P2
M
M
M
O
O
O
C
C
C
• How do we find the intersection of two sets of courses taken? Use AND:
00100011
& 01100001
--------
00100001
49
Bit Masking
• We will frequently want to manipulate or isolate out specific bits in a
larger collection of bits. A bitmask is a constructed bit pattern that we
can use, along with bit operators, to do this.
• Example: how do we update our bit vector to indicate we’ve taken
COMP202?
0 0 1 0 0 0 1 1
00
06
32
02
91
01
02
01
P1
P1
P1
P2
P2
P3
P3
P2
M
M
M
O
O
O
C
C
C
00100011
| 00001000
--------
00101011 50
Bit Masking
#define COMP100 0x1 /* 0000 0001 */
#define COMP106 0x2 /* 0000 0010 */
#define COMP132 0x4 /* 0000 0100 */
#define COMP201 0x8 /* 0000 1000 */
#define COMP202 0x10 /* 0001 0000 */
#define COMP291 0x20 /* 0010 0000 */
#define COMP301 0x40 /* 0100 0000 */
#define COMP302 0x80 /* 1000 0000 */
51
Bit Masking
#define COMP100 0x1 /* 0000 0001 */
#define COMP106 0x2 /* 0000 0010 */
#define COMP132 0x4 /* 0000 0100 */
#define COMP201 0x8 /* 0000 1000 */
#define COMP202 0x10 /* 0001 0000 */
#define COMP291 0x20 /* 0010 0000 */
#define COMP301 0x40 /* 0100 0000 */
#define COMP302 0x80 /* 1000 0000 */
52
Bit Masking
• Example: how do we update our bit vector to indicate we’ve not taken
COMP132?
000 0 1 0 0 0 1 1
06
32
02
91
01
02
01
P1
P1
P1
P2
P2
P3
P3
P2
M
M
M
O
O
O
C
C
C
00100011
& 11011111
--------
00000011
char myClasses = ...;
myClasses = myClasses & ~COMP132; // Remove COMP132 53
Bit Masking
• Example: how do we update our bit vector to indicate we’ve not taken
COMP132?
000 0 1 0 0 0 1 1
06
32
02
91
01
02
01
P1
P1
P1
P2
P2
P3
P3
P2
M
M
M
O
O
O
C
C
C
00100011
& 11011111
--------
00000011
char myClasses = ...;
myClasses &= ~COMP132; // Remove COMP132 54
Bit Masking
• Example: how do we check if we’ve taken COMP301?
0 0 1 0 0 0 1 1
00
06
32
02
91
01
02
01
P1
P1
P1
P2
P2
P3
P3
P2
M
M
M
O
O
O
C
C
C
00100011
& 00000010
--------
00000010
char myClasses = ...;
if (myClasses & COMP301) {...
// taken COMP301! 55
Bit Masking
• Example: how do we check if we’ve not taken COMP201?
0 0 1 0 0 0 1 1
00
06
32
02
91
01
02
01
P1
P1
P1
P2
P2
P3
P3
P2
M
M
M
O
O
O
C
C
C
00100011
& 00010000
--------
00000000
char myClasses = ...;
if (!(myClasses & COMP201)) {...
// not taken COMP201! 56
Bit Masking
• Example: how do we check if we’ve not taken COMP201?
0 0 1 0 0 0 1 1
00
06
32
02
91
01
02
01
P1
P1
P1
P2
P2
P3
P3
P2
M
M
M
O
O
O
C
C
C
00100011 00000000
& 00010000 ^ 00010000
-------- --------
00000000 00010000
char myClasses = ...;
if ((myClasses & COMP201) ^ COMP201) {...
// not taken COMP201! 57
Practice: Bitwise Operations
How can we use bitmasks + bitwise operators to…
0b00001101
1. …turn on a particular 2. …turn off a particular 3. …flip a particular
set of bits? OR set of bits? AND set of bits? XOR
59
Bit Masking
• Bit masking is also useful for integer representations as well. For
instance, we might want to check the value of the most-significant bit,
or just one of the middle bytes.
int j = ...;
int k = j & 0xff; // mask to get just lowest byte
60
Practice: Bit Masking
• Practice 1: write an expression that, given a 32-bit integer j, sets its
least-significant byte to all 1s, but preserves all other bytes.
j | 0xff
61
Practice: Bit Masking
• Practice 1: write an expression that, given a 32-bit integer j, sets its
least-significant byte to all 1s, but preserves all other bytes.
j | 0xff
62
Powers of 2
63
Demo: Powers of 2
is_power_of_2
Lecture Plan
• Casting and Combining Types (cont’d.)
• Byte Ordering
• Bitwise Operators
• Bitmasks
• Bit Shift Operators
65
Left Shift (<<)
The LEFT SHIFT operator shifts a bit pattern a certain number of
positions to the left. New lower order bits are filled in with 0s, and bits
shifted off the end are lost.
8-bit examples:
00110111 << 2 results in 11011100
01100011 << 4 results in 00110000
10010101 << 4 results in 01010000
66
Right Shift (>>)
The RIGHT SHIFT operator shifts a bit pattern a certain number of
positions to the right. Bits shifted off the end are lost.
x >> k; // evaluates to x shifted to the right by k bit
x >>= k; // shifts x to the right by k bits
69
Right Shift (>>)
The RIGHT SHIFT operator shifts a bit pattern a certain number of
positions to the right. Bits shifted off the end are lost.
x >> k; // evaluates to x shifted to the right by k bit
x >>= k; // shifts x to the right by k bits
(1<<2) + (3<<4)
73
Bit Operator Pitfalls
• The default type of a number literal in your code is an int.
• Let’s say you want a long with the index-32 bit as 1:
• This doesn’t work! 1 is by default an int, and you can’t shift an int by
32 because it only has 32 bits. You must specify that you want 1 to be a
long.
74
Recap
• Casting and Combining Types (cont’d.)
• Byte Ordering
• Bitwise Operators
• Bitmasks
• Bit Shift Operators