Reputation: 303
Full disclosure, this is a homework problem and I do not need exact code. I am tasked with reproducing the following code while only using ~ & + <<.
int result = 0;
int i;
for(i = lowbit; i <= highbit; i++)
result |= 1 << i;
return result;
Where lowbit
and highbit
are parameters between 0
and 31
inclusive. If lowbit
is a larger number than highbit
, return 0.
What I have tried so for is the following code
int result = 0;
int negone = ~0x0;
int first = 1 << (lowbit + negone); //the first 1 bit is at the lowbit th location
int last = 1 << (highbit + negone); //the last 1 bit is at the highbit th location
int tick = ~(first + last); //attempting to get all bits in the range of low and highbit.
result = ~(~first & ~tick); //bitwise | without using |
result = ~(~last & ~result);
return result + 1; //the first bit should always be on.
So is there something fundamental I am missing here? In addition to what I have not working this also goes over my limit of 12 operators that I am allowed to use, but I'd like to try and get it working before I even begin to limit the operators.
When I run the test script on this I get errors on most of the tests it is put against including lowbit
and highbit
being equal to each other. Cases where highbit
is the max size and lowbit
is the least size seem to work though.
Any help would be much appreciated.
Upvotes: 0
Views: 748
Reputation: 93496
1) Create a mask with the bits low to high set:
uint32_t mask = ~(~0ul << highbit << 1) & (~0ul << lowbit)
Example: lowbit = 4, highbit = 12 (9 bits)
mask = ~(0xffffffff << 12 << 1) & (0xffffffff << 4)
= ~(0xffff7000) & 0xfffffff0
= 0x00001fff & 0xfffffff0
= 0x00001ff0
2) Apply the mask to the value to be modified, this most simply an |
operation, but that is not a valid operator in this exercise, so must be transformed using De Morgan's forum:
A|B
-> ~(~A & ~B)
:
result = ~(~result & ~mask) ;
It is of course possible to combining the two steps, but perhaps clarity would not then be served.
Upvotes: 1
Reputation: 14
The problem could be that tick = ~(first+last)
does not flip the bit from the lowbit to the highbit.
Maybe we can do something like this:
/* supposed that lowbit = 1, highbit = 2 */
uint32_t negone = ~(0u); /* negone = all 1s */
uint32_t first = negone << lowbit; /* first = ...111110 */
uint32_t last = (1 << (highbit + 1)) + negone; /* last = ...0000111 */
uint32_t tick = last & first; /* tick = ...000110 */
result = ~(~result&~tick); /* Bitwise Or without | as you mentioned. */
It takes 11 bit operations to do this.
p.s. I am wondering why the first bit should be always on.
Edit: In order to avoid undefined operation, we should use unsigned type, like uint32_t
.
Upvotes: -1
Reputation: 35154
The original code generates a block of 1
from lowbit
on until highbit
(inclusive).
This can be achieved without a loop as follows:
int nrOfBits = highbit + ~lowbit + 2; // highbit - lowbit + 1
int shift = (nrOfBits & 0x1f + 1);
int result = ~(~(1 << shift)+1) << lowbit;
The idea is that, for example a range of 8 bits filled up with 1
means a number of 255
, whereas 2^8
is 256
. So - as operator -
is not allowed, we use 2-complement to get -256
, add 1
to get -255
, and turn it back to +255
using 2-complement operator ~
. Then, we just have to shift the block lowbits
left.
Upvotes: 0
Reputation: 144818
negone
should be initialized this way:
uint32_t negone = ~0UL;
You are adding the bit number with a bit pattern in:
int first = 1 << (lowbit + negone); //the first 1 bit is at the lowbit th location
int last = 1 << (highbit + negone);
You should instead compute the 32 bit masks
uint32_t first = negone << lowbit; // all bits below lowbit are 0, others are 1
uint32_t last = negone << highbit << 1; // all bits above highbit are 1, other are 0
The result is obtained by masking the complement of first
with last
:
uint32_t result = ~first & last;
Combining the above steps gives is a direct solution with 7 operators (12 including the parentheses and the assignment), no addition, and no subtraction:
uint32_t result = ~(~0UL << highbit << 1) & (~0UL << lowbit);
I use 0UL
because type unsigned long
is guaranteed to have at least 32 bits, whereas type unsigned int
might have just 16 bits.
Upvotes: 4