This is pretty simple problem, which I assume is homework. @tom made it a bit harder than it needs to be.
You simply want to extract every 4th bit starting from the least significant, ignoring the 3 intervening zeros. I'll give you an algorithm. Writing the code shouldn't be hard:
let x be the hex coded binary number to convert
let val be the binary result value, initially zero
let n be the bit position we're currently finding, initially zero
while x is not zero
let b be the least significant bit of x
update val to be val or (b shifted left by n bits)
increment n
update x to be x shifted right by 4 bits
Here's another approach:
let val be 0
let hex_mask be 1
let bin_mask be 1
while hex_mask is not zero
if (x and hex_mask) is non-zero, then update val to be val or bin_mask
shift hex_mask left 4 bits
shift bin_mask left 1 bit
Addition
Since you say it's not homework, let me show you that the second solution actually is a solution with only bitwise operators if you have a good compiler.
Here's code:
uint16_t hex_coded_binary_value(uint16_t x) {
uint16_t val = 0;
for (uint16_t h = 1, b = 1; h; h <<=4, b <<= 1)
if (x & h) val |= b;
return val;
}
If you compile this with a recent version of Apple clang
, you'll get:
mov eax, edi
and eax, 1
mov ecx, edi
shr ecx, 3
and ecx, 2
or ecx, eax
mov eax, edi
shr eax, 6
and eax, 4
or eax, ecx
shr edi, 9
and edi, 8
lea eax, [rdi + rax]
ret
Note no loops! It's all shift, and, or, add, and move. gcc
uses conditional move instructions, but also no loops.
What's the algorithm the compiler has discovered? If you were coding in C, it would look something like:
val = (x & 1)
| ((x >> (4 - 1)) & (1 << 1))
| ((x >> (8 - 2)) & (1 << 2))
| ((x >> (12 - 3)) & (1 << 3));
This folds to
val = (x & 1) | ((x >> 3) & 2) | ((x >> 6) & 4) | ((x >> 9) & 8);
Note that the result has fewer operations than @tom's solution.
This also compiles to essentially the same as the original, but the C is longer and more error prone. The moral is to trust your compiler.