#include #include #include /*************************************************** * Accessing and modifying individual bits * * Write four functions that allow us to work with * individual bits of a 64-bit unsigned integer: * * 1. is_set determines whether a specified bit * is 0 or 1. * * 2. set changes a specified bit to 1. * * 3. clear changes a specified bit to 0. * * 4. toggle changes a specified bit: * * 0 -> 1 * 1 -> 0. * * Bits are numbered from right to left beginning * with bit 0: * * ... b7 b6 b5 b4 b3 b2 b1 b0 * * Thus, the value * * 12 = 1100 * * has bits 2 and 3 set: * * bit: 3 2 1 0 * ------- * value: 1 1 0 0 * * * CREATING A MASK * * To access bit b, begin with * * 1 * * and shift its 1 bit b positions to the left: * * std::uint64_t{ 1 } << b. * * For example, if b == 3, * * 00000001 << 3 * * produces * * 00001000. * * This gives us a mask having exactly the desired * bit set to 1. * * * ACCESSING A BIT * * To determine whether bit b is set, use bitwise * AND: * * n & mask. * * Every bit other than bit b is forced to 0. * Therefore, * * (n & mask) != 0 * * is true exactly when bit b is 1. * * * SETTING A BIT * * To set bit b to 1, use bitwise OR: * * n |= mask; * * The 1 in the mask forces bit b to 1. All other * bits remain unchanged because they are ORed with * 0. * * * CLEARING A BIT * * To clear bit b, complement the mask and use * bitwise AND: * * n &= ~mask; * * The complemented mask has a 0 in position b and * 1s everywhere else. Thus, bit b is forced to 0 * while all other bits remain unchanged. * * * TOGGLING A BIT * * To toggle bit b, use bitwise XOR: * * n ^= mask; * * XOR with 1 changes * * 0 -> 1 * 1 -> 0, * * while XOR with 0 leaves every other bit * unchanged. * * * VALID BIT POSITIONS * * A std::uint64_t contains exactly 64 bits, numbered * * 0, 1, 2, ..., 63. * * Therefore, each function requires * * bit < 64. * * We use an assertion to document and verify this * precondition. ***************************************************/ // Function declarations int main(); bool is_set( std::uint64_t n, unsigned int bit ); void set( std::uint64_t &n, unsigned int bit ); void clear( std::uint64_t &n, unsigned int bit ); void toggle( std::uint64_t &n, unsigned int bit ); // Function definitions int main() { std::uint64_t n{ 12 }; // 1100 std::cout << is_set( n, 0 ) << std::endl; std::cout << is_set( n, 1 ) << std::endl; std::cout << is_set( n, 2 ) << std::endl; std::cout << is_set( n, 3 ) << std::endl; std::cout << is_set( n, 5 ) << std::endl; set( n, 0 ); set( n, 0 ); toggle( n, 1 ); toggle( n, 2 ); toggle( n, 2 ); toggle( n, 2 ); clear( n, 3 ); clear( n, 3 ); std::cout << n << std::endl; return 0; } /*************************************************** * is_set * * Returns true if the specified bit is 1 and false * if the specified bit is 0. ***************************************************/ bool is_set( std::uint64_t n, unsigned int bit ) { assert( bit < 64 ); std::uint64_t mask{ std::uint64_t{ 1 } << bit }; return (n & mask) != 0; } /*************************************************** * set * * Sets the specified bit to 1. ***************************************************/ void set( std::uint64_t &n, unsigned int bit ) { assert( bit < 64 ); std::uint64_t mask{ std::uint64_t{ 1 } << bit }; n |= mask; } /*************************************************** * clear * * Clears the specified bit by setting it to 0. ***************************************************/ void clear( std::uint64_t &n, unsigned int bit ) { assert( bit < 64 ); std::uint64_t mask{ std::uint64_t{ 1 } << bit }; n &= ~mask; } /*************************************************** * toggle * * Toggles the specified bit: * * 0 -> 1 * 1 -> 0. ***************************************************/ void toggle( std::uint64_t &n, unsigned int bit ) { assert( bit < 64 ); std::uint64_t mask{ std::uint64_t{ 1 } << bit }; n ^= mask; }