This is in fact homework, thank you for any help you can give me.
So the assignment is to implement a series of functions using only bitwise/logical operators, no while loops, no if statements, etc. in C in a certain number of operators. The exact rules are spoilered:
Spoiler:
Each "Expr" is an expression using ONLY the following: 1. Integer constants 0 through 255 (0xFF), inclusive. You are not allowed to use big constants such as 0xffffffff. 2. Function arguments and local variables (no global variables). 3. Unary integer operations ! ~ 4. Binary integer operations & ^ | + << >>
Some of the problems restrict the set of allowed operators even further. Each "Expr" may consist of multiple operators. You are not restricted to one operator per line.
You are expressly forbidden to: 1. Use any control constructs such as if, do, while, for, switch, etc. 2. Define or use any macros. 3. Define any additional functions in this file. 4. Call any functions. 5. Use any other operations, such as &&, ||, -, or ?: 6. Use any form of casting.
You may assume that your machine: 1. Uses 2s complement, 32-bit representations of integers. 2. Performs right shifts arithmetically. 3. Has unpredictable behavior when shifting an integer by more than the word size.
I'm having trouble with two of the functions, logicalNeg and bitCount. The first is to implement the ! operator without actually using !. Bit count is to count the number of set bits. Exact rules again spoilered.
logicalNeg:
Spoiler:
logicalNeg - implement the ! operator, using any of the legal operators except ! Examples: logicalNeg(3) = 0, logicalNeg(0) = 1 Legal ops: ~ & ^ | + << >> Max ops: 12 Rating: 4
bitCount
Spoiler:
bitCount - returns count of number of 1's in word Examples: bitCount(5) = 2, bitCount(7) = 3 Legal ops: ! ~ & ^ | + << >> Max ops: 40 Rating: 4
int count = 0; count += x&0x01; x = x>>1; count += x&0x01; x = x>>1; count += x&0x01; x = x>>1; count += x&0x01; x = x>>1; count += x&0x01; x = x>>1; count += x&0x01; x = x>>1; count += x&0x01; x = x>>1; count += x&0x01; x = x>>1; count += x&0x01; x = x>>1; count += x&0x01; x = x>>1; count += x&0x01; x = x>>1; count += x&0x01; x = x>>1; count += x&0x01; x = x>>1; count += x&0x01; x = x>>1; count += x&0x01; x = x>>1; count += x&0x01; x = x>>1; count += x&0x01; x = x>>1; count += x&0x01; x = x>>1; count += x&0x01; x = x>>1; count += x&0x01; x = x>>1; count += x&0x01; x = x>>1; count += x&0x01; x = x>>1; count += x&0x01; x = x>>1; count += x&0x01; x = x>>1; count += x&0x01; x = x>>1; count += x&0x01; x = x>>1; count += x&0x01; x = x>>1; count += x&0x01; x = x>>1; count += x&0x01; x = x>>1; count += x&0x01; x = x>>1; count += x&0x01; x = x>>1; count += x&0x01; x = x>>1; return count;
logicalNeg works for every case but -1, because for zero and -1 the first two statements give an equivalent OR statement.
bitCount works fine, but it's more than twice the allowed operators, I've been trying to figure out a way to condense what I have, but I haven't had any luck. It's the while loop method extended.
Here's a quick idea for the not: try ORing all the bits together, then doing a bitwise not on the result.
Yes, I realize the naive way of ORing all the bits together requires more operations than you're allowed, but if you're clever with your shifting, I'm sure you can see a way to drastically cut the number of ORs required
Err, never mind, I think this is still too many ops
This should work: bitwise not, and all bits together with clever shifting
quint has the right idea... you want to build a number which has a bit that's the logical or of all the bits in your original number. Obviously, to do this the naive way would use too many operations, but remember that your bitwise or is able to do many logical ors all at once.
If that's too obscure, here's a more direct hint:
Spoiler:
When you come in, you have a number that's True iff there's a 1 anywhere in the 32 bits. How many operations would it take you to build a number such that the original number should be treated as True iff this new number has a 1 in the last, say, 16 bits?
As for bit-count... the traditional trick for doing this one without any branches requires large constants to use as bitmasks, which you're not allowed... I think you have enough operands allowed to build them up from individual bytes, though...
[edit] Just to confirm it is possible... I have a working logicalNot using 12 operations, and bitCount using 36.
While no one overhear you quickly tell me not cow cow. but how about watch phone?
I very much like the direction you've taken with your logicalNeg function. (I would like to think that I would have come up with it myself, but I suspect I wouldn't have.) Your fundamental approach to detecting x == 0 is sound; it's just the execution that doesn't quite come together. Consider replacing the first two declarations in your proposed solution with the following:
Think of i as "before incrementation" and j as "after" and work through what the sign bits of i and j look like for different values of x. The remaining logic should quickly suggest itself.
For bitCount, here's a fragment of code that might suggest an alternative attack to the problem:
Assuming brackets don't count as operators, it's possible to do bitcount using 22 bitwise operators. It's very similar to the way you wrote your previous code.
quintopia, your second method worked perfectly, thanks for the help. Got it in 12 ops. ATCG, the problem wasn't with 0, it was with -1. For both these values the OR statement would be equivilant, just with i and j reversed. Your code probably fixes this error too though, and it seems interesting so I'll see if I can work it out along with the bitcount.
mr-mitch, brackets suggest arrays, functions, or control statements, none of which are allowed for the assignment. Am I wrong about what you're thinking?
Thanks again for all your help, I'll keep you posted.
mr-mitch, brackets suggest arrays, functions, or control statements, none of which are allowed for the assignment. Am I wrong about what you're thinking?
I was referring to using brackets for precendence.
eg x >> 1 + 1 is different to (x>>1) + 1 in most compilers (if not all).
mr-mitch wrote:Assuming brackets don't count as operators, it's possible to do bitcount using 22 bitwise operators. It's very similar to the way you wrote your previous code.
Hi I am new to the forums and have been lurking for awhile but finally found the need to participate. BTW my favorite comic was when the man tells his wife to make him a sandwich and she says no and then he says sudo make me a sandwich and she says ok hahahaha.
Ok I know this topic has been dead for awhile but I am doing something very similar to bitCount, actually it’s the same thing with the same restrictions. So far I can count the bits but I use about 50+ operations and I can only use 40ish.
So I read the hint about making the mask be 0xFF, mask << 24 then mask >> 24 to make it 0x111111111111111… and then do basically the same thing. I don’t know how this saves any instructions and I have been working on this for awhile but cant find the clue to keep me going forward. Any suggestions????
One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision - BR
Last edited by JHVH on Fri Oct 23, 4004 BCE 6:17 pm, edited 6 times in total.
int negtest(unsigned int i) { // The *unsigned* int type is important here // ~0 = 0xffffffff = -1 // MSB of (i + ~0) ^ i flips on i=0 and i=-2147483648 (INT_MIN) // &'ed with ~i to remove the 0x8000 case // shifting by 31 to get 0 or 1 return (((i + ~0) ^ i) & ~i) >> 31; }
That's because XOR of a bit with 1 is always the bit inverted (1 ^ 1 = 0; 0 ^ 1 = 1). This only works if "logical negation" is to be understood in the C sense (0 = false, everything else = true).
That's because XOR of a bit with 1 is always the bit inverted (1 ^ 1 = 0; 0 ^ 1 = 1). This only works if "logical negation" is to be understood in the C sense (0 = false, everything else = true).
That inverts all the bits.
So invert(-1) = 0x00000000 invert(0) = 0xffffffff invert(1) = 0xfffffffe
While !(-1) = 0 !0 = 1 !1 = 0
As the task is to "implement the ! operator", I don't think that qualifies.
What number, when negated, is non-negative, and it non-negative itself? ((-i)|(i))>>31 -i is (~i+1) ((~i+1)|i)>>31 which is 1 iff i is non-zero.
Now, we don't want that value, but the opposite: (~((~i+1)|i))>>31 which is 5 ops.
Now, we could expand the ~: (~(~i+1)&~i)>>31 which is also 5 ops (and one temporary variable so we don't double-compute ~i).
You'll note that ~(~i+1) is similar to (i-1) above. -x = (~x+1), so ~(~i+1) = ~(-i). -x-1 = ~x, so ~(-i) = -(-i)-1 = i-1.
This shows how ~(~i+1) = (i+~0) = i-1.
One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision - BR
Last edited by JHVH on Fri Oct 23, 4004 BCE 6:17 pm, edited 6 times in total.