int
has more than tree bits, so you must mask the result of a bitwise negation like this:
int flip(int n) {
// bitwise AND with 0b111 = 7, this will clear all but the last 3 bits
return ~n & 0b111;
}
The reason you got -6 is because int
is typically represented in two's complement, where -6
is all 1
-bits but ends with 010
. You must remove these leading 1
-bits to get the correct result.
Generally, I would recommend not using bitwise operations with signed numbers and instead do the following:
unsigned flip(unsigned n) {
return ~n & 0b111;
}
// this version works with any number of bits, not just 3
unsigned flip(unsigned n, unsigned bits) {
unsigned mask = (1 << bits) - 1;
return ~n & mask;
}
If you don't know how many bits your number has, you must first find the most significant bit. In the most naive way, it can be done like this:
unsigned log2(unsigned val)
{
unsigned result = 0;
while (val >>= 1) {
++result;
}
return result;
}
unsigned variable_flip(unsigned n) {
return flip(n, log2(n));
}
You can find more efficient solutions here.
For example:
unsigned log2_debruijn(uint32_t val) {
static const unsigned MultiplyDeBruijnBitPosition[32] = {0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30,
8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31};
// first round down to one less than a power of 2
// this step is not necessary if val is a power of 2
val |= val >> 1;
val |= val >> 2;
val |= val >> 4;
val |= val >> 8;
val |= val >> 16;
return MultiplyDeBruijnBitPosition[(val * uint32_t{0x07C4ACDD}) >> 27];
}