#include #include #include /*************************************************** * Select and shift bits * * Given two 64-bit unsigned integers: * * - selector determines which bit positions are * selected, and * * - value contains the bits to be selected. * * For every 1 bit in selector, take the bit in the * corresponding position of value and pack those * selected bits into the rightmost positions of the * result. * * * A SMALL EXAMPLE * * Suppose * * selector = 10110100 * value = 01101101 * * Reading the bits from right to left, selector has * 1 bits in positions * * 2, 4, 5, and 7. * * The corresponding bits of value are * * position: 7 5 4 2 * value bit: 0 1 0 1 * * These selected bits are packed together: * * result = 0101. * * * TWO MASKS * * We use two masks. * * The first, * * input_mask, * * moves through every bit position of selector and * value: * * 00000001 * 00000010 * 00000100 * 00001000 * ... * * The second, * * output_mask, * * identifies the next available position in result. * * Unlike input_mask, output_mask advances only when * we encounter a 1 bit in selector. * * * FOR EACH BIT * * If * * (selector & input_mask) != 0, * * then the current bit position has been selected. * * We then examine the corresponding bit of value: * * (value & input_mask) != 0. * * If that bit is 1, we set the position identified * by output_mask: * * result |= output_mask; * * Whether the selected bit of value is 0 or 1, we * then shift output_mask one position to the left: * * output_mask <<= 1; * * Thus, the selected bits are packed consecutively * into result. * * * NOTICE THE DIFFERENCE * * input_mask advances during every iteration because * every input position must be examined. * * output_mask advances only when the corresponding * bit of selector is 1 because only selected bits * occupy positions in the result. * * * For example, the values used below are * * selector = 56232523235 * value = 23535131353 * * and the selected and packed bits produce * * 479897. ***************************************************/ // Function declarations int main(); std::uint64_t select_and_shift( std::uint64_t selector, std::uint64_t value ); // Function definitions int main() { std::uint64_t selector{ UINT64_C( 56232523235 ) }; std::uint64_t value{ UINT64_C( 23535131353 ) }; std::uint64_t result{ select_and_shift( selector, value ) }; std::cout << "Selector: " << std::bitset<64>( selector ) << std::endl; std::cout << "Value: " << std::bitset<64>( value ) << std::endl; std::cout << "Result: " << std::bitset<64>( result ) << std::endl; std::cout << " " << result << std::endl; return 0; } /*************************************************** * select_and_shift * * For each 1 bit in selector, select the * corresponding bit in value and pack the selected * bits into the rightmost positions of the result. ***************************************************/ std::uint64_t select_and_shift( std::uint64_t selector, std::uint64_t value ) { std::uint64_t result{ 0 }; std::uint64_t output_mask{ 1 }; for ( std::uint64_t input_mask{ 1 }; input_mask != 0; input_mask <<= 1 ) { if ( (selector & input_mask) != 0 ) { // The current position has been selected. // If the corresponding bit in value is 1, // set the next available bit in result. if ( (value & input_mask) != 0 ) { result |= output_mask; } // Advance to the next position in result // only after a bit has been selected. output_mask <<= 1; } } return result; }