class: center, title-slide
## CSCI-UA 480: APS ## Algorithmic Problem Solving
## Bitmasks .author[ Instructor: Joanna Klukowska
] .license[ Copyright 2020 Joanna Klukowska. Unless noted otherwise all content is released under a
[Creative Commons Attribution-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-sa/4.0/).
Background image by Stewart Weiss
] --- layout:true template: default name: section class: inverse, middle, center --- layout:true template: default name: challenge class: challenge --- layout:true template: default name: poll class: inverse, full-height, center, middle --- layout:true template: default name: breakout class: breakout --- layout:true template:default name:slide class: slide .bottom-left[© Joanna Klukowska. CC-BY-SA.] --- ## Questions - homework 2 questions? - comments about homework 1? - any other questions? -- ----- - please, do not remove posts from Ed - read the problems carefully; reread the input and output description after you write your code and make sure that your code follows those instruction - use tools that help you figure out where your program might be having issues, ex. `valgrind` - read warnings produced by your compiler (and ask the compiler for as many warnings as possible) --- class: middle, center ## Bits, bit operations, bit masks --- ## Bit operations ``` 0101 0101 0101 0011 0011 0011 0101 & | ^ ~ ---- ---- ---- ---- 0001 0111 0110 1010 ``` -- left shift << ``` 00101 <<2 10100 ``` -- right shift >> .small[in C/C++, the right shift operator is performing logical or arithmetic shift depending on the context; in Java, there are two right shift operators: `>>` performs the arithmetic shift, `>>>` performs the logical shift] ``` 001010 >>2 000010 ``` -- - shifting is equivalent to multiplying by powers of two (but faster) - WARNING: avoid shifting out of the type range --- ## Bit-mask A __bit mask__ of the form `1 << k` has one bit on (i.e., equal to 1) in the `k`
th
position and all other bits off (i.e., equal to 0). - to determine if a bit at the `k`
th
position in a particular value is on or off, we can use this bit mask and the bitwise `and` operator: `x & (1 << k)` example: ``` for (int k = 31; k >=0; k--) { if (x & (1 << k) ) cout << "1"; else cout << "0"; } ``` What does this code do? -- It prints the binary represetnation of `x` (assuming that `x` is a 32-bit variable). --- ## Bit-mask continued Modifying bits within a value: - set the `k`
th
bit to be on (regardless of what it was before): ??? - set the `k`
th
bit to be off (regardless of what it was before): ??? - set the `k`
th
bit to be on if it is currently off, and to be off if it is currently on (just flip that bit to the opposite): ??? - invert all bits after the last (least significant) one bit: ??? - set the last (least significant) one bit in x to 0: ??? - test if x is a power of two: ??? --- ## Bit-mask continued Modifying bits within a value: - set the `k`
th
bit to be on (regardless of what it was before): `x = x | (1 << k)` - set the `k`
th
bit to be off (regardless of what it was before): `x = x & ~(1 << k)` - set the `k`
th
bit to be on if it is currently off, and to be off if it is currently on (just flip that bit to the opposite): `x = x ^ (1 << k)` - invert all bits after the last (least significant) one bit: `x = x | (x-1)` - set the last (least significant) one bit in x to 0: `x & (x - 1)` - test if x is a power of two: `x & (x - 1) == 0` --
`(1 << k)` is a 32-bit mask (1 is an `int`) to use a 64-bit bit mask: use (`1L << k`) -- .small[ The last three operations depend on understanding of the relationship between `x` and `x-1` in binary. Here are some examples: |decimal | binary ||decimal | binary ||decimal | binary | |---|---||---|---||---|---| |45 | 0010 1101 || 32 | 0010 0000 || 36 | 0010 0100 | |44 | 0010 1100 || 31 | 0001 1111 || 35 | 0010 0011 | (when we compare `x` to `x-1` all the bits starting at the least significant `1` bit are flipped) ] --- ## Useful library functions, C/C++ - `__builtin_clz(x)`: the number of zeros at the beginning of the bit representation - `__builtin_ctz(x)`: the number of zeros at the end of the bit representation - `__builtin_popcount(x)`: the number of ones in the bit representation - `__builtin_parity(x)`: the parity (even or odd) of the number of ones in the bit representation -- example ``` int x = 5328; // 00000000000000000001010011010000 cout << __builtin_clz(x) << "\n"; // 19 cout << __builtin_ctz(x) << "\n"; // 4 cout << __builtin_popcount(x) << "\n"; // 5 cout << __builtin_parity(x) << "\n"; // 1 ``` -- Add `l` suffix to the above functions to use the `long` versions instead of `int`. --- ## Useful library functions, Java in `Integer` class : - `int bitCount(int i)`
Returns the number of one-bits in the two's complement binary representation of the specified int value. - `int highestOneBit(int i)`
Returns an int value with at most a single one-bit, in the position of the highest-order ("leftmost") one-bit in the specified int value. - `int lowestOneBit(int i)`
Returns an int value with at most a single one-bit, in the position of the lowest-order ("rightmost") one-bit in the specified int value. - `int numberOfLeadingZeros(int i)`
Returns the number of zero bits preceding the highest-order ("leftmost") one-bit in the two's complement binary representation of the specified int value. ... --- template: challenge ## Exercises - Write a code fragment that sets (turns on) every bit in an even position in an integer mask. (Can you define such a mask in one _step_?) - Compute the _distance_ between two bitmasks, i.e., how many positions in the two values are different? (this is known as the [hamming distance](https://en.wikipedia.org/wiki/Hamming_distance)) --- template: challenge ## Exercises - Write a code fragment that sets (turns on) every bit in an even position in an integer mask. ```C++ x = 0; for (int i=0; i < 31; i=i+2) { x = x | (1 << i); } ``` ```C x = 0x55555555; ``` - Compute the _distance_ between two bitmasks, i.e., how many positions in the two values are different? (this is known as hamming distance) `Integer.bitCount ( x ^ y )` --- class: middle, center ## Sets --- ## Representing sets Any subset of a set $${0, 1, 2, 3, ..., n-1 }$$ can be represented by an `n`-bit integer. The bits of a number indicate if the element is present in the set or not. __Example__ `0000000000000000000100100001011` represents the subset {0, 1, 3, 8, 11} To create such a subset representation use code as follows: ```C++ int x = 0; x |= (1 << 0); x |= (1 << 1); x |= (1 << 3); x |= (1 << 8); x |= (1 << 11); ``` --- ## Set operations How can the following operations be performed on the sets represented by integers: - set intersection $A\cap B$ (what do the two sets have in common) - set union $A\cup B$ (all elements in either one, or both sets) - set difference $A \setminus B$ (all elements in A that are not in B) -- Assume that two integers `a` and `b` represent two sets (max number of elements in each set is 32). - `a & b` is the intersection - `a | b` is the union - `a & (~b)` is the difference --- template: challenge ## Exercises - Create two sets $a={1, 3, 8, 11, 23, 27 }$ and $b={1, 2, 4, 11, 15, 27}$. Compute their union, intersection and difference. For each print the content of the set and its size. - List all possible subsets of a set ${0,1,2,...,31}$. - List all possible subsets of a set ${0,1,2,...,31}$ that have exactly 7 elements. --- class: middle, center ## Library Classes --- ## Library Classes, C++ .left-column2-small[ [`bitset`](http://www.cplusplus.com/reference/bitset/bitset/) in C++ .small[ Bit access - `operator[]` Access bit - `count` Count bits set - `size` Return size - `test` Return bit value - `any` Test if any bit is set - `none` Test if no bit is set Bit operations - `set` Set bits - `reset` Reset bits - `flip` Flip bits - overloaded operators (see code example from [Cplusplus.com](http://www.cplusplus.com/reference/bitset/bitset/operators/) on the side ) - ... ] ] .right-column2-large[ ```C++ #include
// cout #include
// string #include
// bitset using namespace std; int main () { bitset<4> foo (string("1001")); bitset<4> bar (string("0011")); cout << (foo ^= bar) << '\n'; // 1010 (XOR,assign) cout << (foo &= bar) << '\n'; // 0010 (AND,assign) cout << (foo |= bar) << '\n'; // 0011 (OR,assign) cout << (foo <<= 2) << '\n'; // 1100 (SHL,assign) cout << (foo >>= 1) << '\n'; // 0110 (SHR,assign) cout << (~bar) << '\n'; // 1100 (NOT) cout << (bar << 1) << '\n'; // 0110 (SHL) cout << (bar >> 1) << '\n'; // 0001 (SHR) cout << (foo == bar) << '\n'; // false (0110==0011) cout << (foo != bar) << '\n'; // true (0110!=0011) cout << (foo & bar) << '\n'; // 0010 cout << (foo | bar) << '\n'; // 0111 cout << (foo ^ bar) << '\n'; // 0101 return 0; } ``` ] --- ## Library Classes, Java [`BitSet`](https://docs.oracle.com/javase/8/docs/api/java/util/BitSet.html) in Java - `clear()` Sets all of the bits in this BitSet to false. - `flip(int bitIndex)` Sets the bit at the specified index to the complement of its current value. - `get(int bitIndex)` Returns the value of the bit with the specified index. - `intersects(BitSet set)` Returns true if the specified BitSet has any bits set to true that are also set to true in this BitSet. - `nextSetBit(int fromIndex)` Returns the index of the first bit that is set to true that occurs on or after the specified starting index. - `set(int fromIndex, int toIndex, boolean value)` Sets the bits from the specified fromIndex (inclusive) to the specified toIndex (exclusive) to the specified value. - ... --- class: middle, center ## Example Application: ## Prime Numbers --- template: challenge ## Primality Test __Task__: given a number N determine if it is prime or not -- Very naive algorithm: $O(N)$ (check if any of the numbers from 1 to N is a divisor) Better algorithm: $O(\sqrt(N))$ (check if any of the numbers from 1 to $\sqrt(N)$ is a divisor) Even better algorithm: $O(\sqrt(N))$ (check if any of the numbers from 1 to $\sqrt(N)$ is a divisor, but only test the odd values after testing 2) --- template: challenge ## Prime numbers __Task:__ Generate all prime numbers in the range from 0 to N -- Very naive algorithm: $O(N^2)$ Less naive algorithm: $O(N\sqrt(N))$ -- __Sieve of Eratosthenes__ - $O(N \log\log N)$ - Algorithm: - set all values in the range to _probably prime_ - set 0 and 1 to be ~~not prime~~ - for p in 2:N - if p is _probably prime_ - set p to __definitely prime__ - set all multiples of p (except for p itself) to ~~not prime~~ --- ## Sieve of Eratosthenes - Example: N = 20 - ~~0~~ ~~1~~ _2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20_ -- - ~~0~~ ~~1~~ __2__ _3_ ~~4~~ _5_ ~~6~~ _7_ ~~8~~ _9_ ~~10~~ _11_ ~~12~~ _13_ ~~14~~ _15_ ~~16~~ _17_ ~~18~~ _19_ ~~20~~ -- - ~~0~~ ~~1~~ __2__ __3__ ~~4~~ _5_ ~~6~~ _7_ ~~8~~ ~~9~~ ~~10~~ _11_ ~~12~~ _13_ ~~14~~ ~~15~~ ~~16~~ _17_ ~~18~~ _19_ ~~20~~ -- - ~~0~~ ~~1~~ __2__ __3__ ~~4~~ __5__ ~~6~~ _7_ ~~8~~ ~~9~~ ~~10~~ _11_ ~~12~~ _13_ ~~14~~ ~~15~~ ~~16~~ _17_ ~~18~~ _19_ ~~20~~ -- - ~~0~~ ~~1~~ __2__ __3__ ~~4~~ __5__ ~~6~~ __7__ ~~8~~ ~~9~~ ~~10~~ _11_ ~~12~~ _13_ ~~14~~ ~~15~~ ~~16~~ _17_ ~~18~~ _19_ ~~20~~ -- - ~~0~~ ~~1~~ __2__ __3__ ~~4~~ __5__ ~~6~~ __7__ ~~8~~ ~~9~~ ~~10~~ __11__ ~~12~~ _13_ ~~14~~ ~~15~~ ~~16~~ _17_ ~~18~~ _19_ ~~20~~ -- - past the halfway point, all the remaining probably primes are definitely prime
~~0~~ ~~1~~ __2__ __3__ ~~4~~ __5__ ~~6~~ __7__ ~~8~~ ~~9~~ ~~10~~ __11__ ~~12~~ __13__ ~~14~~ ~~15~~ ~~16~~ __17__ ~~18~~ __19__ ~~20~~ -- - Can we stop before a half-way point? -- - stop after reaching $\sqrt(N)$