Primitive Data Part 3 (logic operations, shifting, bit maps)

advertisement
cs3843
syllabus
lecture notes
programming
assignments
recitations
Logic Operations in C
a && b Logical and. If a is non-zero and b is non-zero, result is 1;
otherwise, 0.
a || b
Logical or. If either a is non-zero or b is non-zero, result
is 1; otherwise, 0.
!a
Logical not. If a zero, result is 1; otherwise, 0.
Bit-Level Logic Operations in C
These operations are performed on each bit position rather than
considering whether the operand (as a whole) is zero or non-zero.
a&b
a|b
~a
Bit-wise and. Each bit position is examined. If
corresponding bits in a and b are both 1, the bit in the
corresponding position for the result is set to 1;
otherwise, it is set to 0.
Bit-wise or. Each bit position is examined. If
corresponding bits in a and b are both 0, the bit in the
corresponding position for the result is set to 0;
otherwise, it is set to 1.
Bit-wise not. Each bit position in a is examined. If the
bit is 1, the bit in the corresponding position for the
result is set to 0; otherwise, it is set to 1.
De Morgan's Laws
1. "not (a and b)" is the same as "(not a) or (not b)"
2. "not (a or b)" is the same as "(not a) and (not b)"
homework
a
00
00
08
08
b
00
03
03
00
set up
a && b
0
0
1
0
a || b
0
1
1
1
!a
1
1
0
0
The table below shows the values in HEX.
a
b
a & b
a | b
~a
a && b
0000 0000
0000
0000
FFF
0000
F
0000 0300
0000
0300
FFF
0000
F
0802 0307
0002
0B07
F7F
0001
D
ABCD 2345
?
?
?
0001
a || b
0000
! a
0001
0001
0001
0001
0000
0001
0000
Is there an easy way for us to bit-wise not a hexadecimal number?
x
~x
x
~x
0
F
8
7
1
E
9
6
2
D
A
5
3
C
B
4
4
B
C
3
5
A
D
2
6
9
E
1
7
8
F
0
1. Use De Morgan's Laws to rewrite each of the following:
1.1 ! (X != 5 && Y == 'N')
1.2 ! (X == 100 || Z == 200)
2. Suppose someone requests all students except those having either a GPA <
3.0 or PAYMENT_HOLD = 'Y'. How do you write the condition for what to
accept?
Shifting Operations
C supports bitwise shifts:
value << k Left shift. Shifts the value to the left k bits,
padding with k 0s on the right side.
Value
(binary)
value << 2
value << 4
value >> 4
(logical)
0110 0111
1001 1100
0111 0000
0000 0110
value >> 4
(arithmetic
)
0000 0110
1001 0101
value >> k
Right shift. Shifts the value to the right k bits;
however, the padding on the left side is
implementation dependent. It either always pads
the left side with k 0s or it pads the left side with
whatever is in the leftmost position of value. The
later is known as an arithmetic right shift (i.e.,
propagating the sign). The former (always
padding with k 0s) is known as a logical right shift.
Multiplying Integers By Powers of 2
On most machines, addition and shifting is at least ten times faster
than integer multiplication. Most compilers will attempt to
optimize multiplications by constants with equivalent shifts and
additions.
Note: When multiplying by a variable (instead of a constant), the
compiler would generate a multiplication.
0101 0100
0101 0000
0000 1001
1111 1001
How would you force the value to be a logical right shift?
It would be easy for a compiler to replace
iVal * 2
with iVal << 1
iVal * 4
with iVal << 2
So, for a constant equivalent to 2 k:
iVal * 2k
is the same as iVal << k
Value
(decimal)
24
100
-3
Value (binary
with 16 bits)
00000000 00011000
00000000 01100100
11111111 11111101
multiplying by 4
value << 2
00000000 01100000
00000001 10010000
11111111 11110100
multiplying by 8
value << 3
00000000 11000000
00000011 00100000
11111111 11101000
To be faster than multiplication, how would you multiply iVal * 5?
For w=8, 5 = (0000 0101)
Using shifts, adds, and/or subtracts, what could we do?
?
To be faster than multiplication, how would you multiply iVal * 7?
?
Dividing by Powers of 2
On most machines, shifting is more than 30 times faster than
integer division.
With integer division, our quotient (result) is an integer without a
value to the right of a decimal point. (e.g., 15 / 4 is 3)
For positive values, dividing by a power of 2 is much faster using
shifting.
With integer division, the result is truncated.
5/2 would be 2.5 for real arithmetic. truncating is 2
-5/2 would be -2.5 for real arithmetic, truncating is -2.
Value
(decimal)
24
100
Value (binary
with 16 bits)
00000000 00011000
00000000 01100100
dividing
value >>
00000000
00000000
by 4
2
00000110
00011001
dividing
value >>
00000000
00000000
by 8
3
00000011
00001100
Other than dividing by powers of 2, can division be replaced by a faster
combination of shifts and adds?
Except in rare cases, no.
Truncating can lead to some interesting compiler-generated
assembly language code. We will see that when we look at
assembly language later in the course.
Bit Map
A bit map is a contiguous list of bits where each bit has a meaning.
If it needs <= 32 bits, we will use a unsigned long to represent it.
Suppose there are 30 students in a class. Each bit position could
represent a student. We might have the following bit maps:
ulFrBitMap (FR 14788020)
00010100 01111000 10000000 00100000
ulSoBitMap (SO 0A814448)
00001010 10000001 01000100 01001000
ulJrBitMap (JR 01042813)
00000001 00000100 00101000 00010011
ulSrBitMap (SR 00021304)
00000000 00000010 00010011 00000100
Suppose we also
ulGradeABitMap
00001001
ulMajorCSBitMap
00001000
have these bit maps:
(A
05580F3C)
10011000 00001111 00111100
(CS 08914A29)
10010001 01001010 00101001
Setting a Bit Position in a Bit Map
To set a bit (turn it ON) in a bit map in position k (from the right):
ulBitMap |= 1 << k;
unsigned long ulBitMap = 0x00000000;
int k = 1;
int bBit = 0;
ulBitMap |= 1 << k;
// set a bit it position k
printf("after setting position %d, bit map is %08X\n"
, k, ulBitMap);
k = 5;
ulBitMap |= 1 << k;
// set a bit it position k
printf("after setting position %d, bit map is %08X\n"
, k, ulBitMap);
k = 4;
ulBitMap |= 1 << k;
// set a bit it position k
printf("after setting position %d, bit map is %08X\n"
, k, ulBitMap);
k = 0;
ulBitMap |= 1 << k;
// set a bit it position k
printf("after setting position %d, bit map is %08X\n"
, k, ulBitMap);
k = 20;
ulBitMap |= 1 << k;
// set a bit it position k
printf("after setting position %d, bit map is %08X\n"
, k, ulBitMap);
k = 30;
ulBitMap |= 1 << k;
// set a bit it position k
How can we determine students (who are in the class) who are either Jr or
Sr?
?
How can we determine students who are not seniors?
?
How can we determine students who are CS majors, seniors, and are making an
A?
?
How can we determine students who are not CS majors, but they are making an
A?
?
printf("after setting position %d, bit map is %08X\n"
, k, ulBitMap);
//Output
after
after
after
after
after
after
Clearing A Bit Position in a Bit Map
To clear a bit (turn it OFF) in a bit map in position k (from the
right):
ulBitMap &= ~(1 << k);
What did that do?
setting
setting
setting
setting
setting
setting
position
position
position
position
position
position
1, bit map is 00000002
5, bit map is 00000022
4, bit map is 00000032
0, bit map is 00000033
20, bit map is 00100033
30, bit map is 40100033
// clearing position k
k = 4;
ulBitMap &= ~(1 << k);
printf("after clearing position %d, bit map is %08X\n"
, k, ulBitMap);
k = 1;
ulBitMap &= ~(1 << k);
printf("after clearing position %d, bit map is %08X\n"
, k, ulBitMap);
//Output
after clearing position 4, bit map is 40100023
after clearing position 1, bit map is 40100021
Accessing a Bit Position in a Bit Map
To access a bit in a bit map at position k:
ulBit = ulBitMap & (1 << k);
Note that the actual value of ulBit will be either 0 or non-zero. If
position 3 is ON and we execute:
ulBit = ulBitMap & (1 << 3);
The value of ulBit will be 8.
If we want the value to be 0 or 1 instead, we can also logical and it
with 1.
bBit = (ulBitMap & (1 << k) ) && 1;
Exclusive OR (XOR)
The exclusive or operator means "one or the other but not both".
C provides a bit level xor using the ^ symbol.
// accessing a bit at a position
ulBitMap = 0x401002A9;
k = 2;
bBit = (ulBitMap & (1 << k)) && 1;
printf("for bit position %d, bit map is %08X, bit is %d\n"
, k, ulBitMap, bBit);
k = 3;
bBit = (ulBitMap & (1 << k)) && 1;
printf("for bit position %d, bit map is %08X, bit is %d\n"
, k, ulBitMap, bBit);
//Output
for bit position 2, bit map is 401002A9, bit is 0
for bit position 3, bit map is 401002A9, bit is 1
a
0
0
1
1
b
0
1
0
1
a and b
0
0
0
1
a or b
0
1
1
1
a xor b
0
1
1
0
// toggle a bit using exclusive or
Suppose we want to toggle a bit in position k. If it was 1, it should
be toggled to 0. If it was 0, it should be toggled to 1. A toggle in C
is:
ulBitMap ^= 1 << k;
ulBitMap = 0x401002A9;
k = 10;
ulBitMap ^= 1 << k;
printf("after toggling position %d, bit map is %08X\n"
, k, ulBitMap);
k = 5;
ulBitMap ^= 1 << k;
printf("after toggling position %d, bit map is %08X\n"
, k, ulBitMap);
k = 10;
ulBitMap ^= 1 << k;
printf("after toggling position %d, bit map is %08X\n"
, k, ulBitMap);
//Output
after toggling position 10, bit map is 401006A9
after toggling position 5, bit map is 40100689
after toggling position 10, bit map is 40100289
Download