tags:

views:

276

answers:

12

I tried doing this in C:

    int val = 0xCAFE;
int uc = val & 14;


if (val & 15 == 15 || val & 7 == 7 || val & 11 == 11|| val & 13 == 13 || val & 14 == 14){
    printf("asdjfkadscjas \n");
}

However this is not printing the random string as it should. It worked for 15,7,11,13 tho.

If anyone knows of a better way that would be helpful. I am bad with bitwise operator.

Thanks

A: 

Psuedocode:

int set = 0;
for(i = 0 to 3)
    set++ if val & (1<<i)
if(set >= 3)
    ...
Anon.
A: 
count  =  (val >> 1) & 1 + (val >> 2)&1 + (val >> 3)&1 + (val&1)

or

count  =  precalculated_counts[val & 0x0F];
Keith Nicholas
woops, just a sec, not quite correct yet
Keith Nicholas
Needs some ampersands.
Anon.
+6  A: 

You're having an operator precedence problem, not an operation problem. == is of higher precedence than &:

if ((val & 15) == 15 || (val & 7) == 7 || ...

Also, you don't need to check for 15.

Ignacio Vazquez-Abrams
why no check for 15?
SuperString
Because if all 4 bits are set then 3 are definitely set, and the four checks for 3 bits will catch it.
Ignacio Vazquez-Abrams
15 includes all four bits, so it will be picked up by a following test (i.e. 7).
dreamlax
Precedence rule #1: multiplication and division before addition and subtraction. Everything else gets parens. While I may not follow this rule of thumb 100% of the time, I do generally follow it. What's the point of memorizing the precedence of all those damn operators, just so it can bite me in the ass when I don't get it right?
Michael Burr
+2  A: 

The comparison operator has precedence to the bitwise and operator, so put parens around the & operator:

if( (val & 15) == 15 || (val & 14) == 14 || ... ) {
    printf( "random string...\n" );
}
frunsi
By quotes I think you mean brackets :)
dreamlax
Yes, true, fixed it :)
frunsi
Actually, those are parentheses. Braces are: {}, Brackets are [] and parentheses are ().
Jerry Coffin
@Jerry: Where I come from, brackets are (), square brackets are [], and curly brackets are {}. They're all brackets.
dreamlax
@dreamlax - Jerry's terminology (or maybe 'parens' instead of 'parentheses') is what's generally used when discussing the C/C++ language (and it's the terminology used in the language standards). Your definitions might be acceptable when talking about punctuation in general, but when discussing the C language it would be quite confusing to refer to parentheses as 'brackets'. The "curly brackets" term would probably cause little or no confusion.
Michael Burr
j_random_hacker
@j_random_hacker: wtf? Come on, this answer is about the parens only. I added a "..." to clarify this.
frunsi
@frunsi: Say "WTF?" all you want. The "..." makes all the difference.
j_random_hacker
A: 
unsigned nNumOfBitEnabled=0;
    for(unsigned nBit=0; nBit<4; ++nBit)
    {
        // Check bit state
        if ((val >> nBit) & 0x1)
        {
            ++nNumOfBitEnabled;
        }
    }
YeenFei
+1  A: 

A simple way to do this, which also shows your intent clearly, would be:

if (!!(val & 0x01) + !!(val & 0x02) + !!(val & 0x04) + !!(val & 0x08) >= 3)
caf
I like this for clarity.
j_random_hacker
It's clear as long as you understand the meaning and outcome of the double bang.
dreamlax
Maybe a quadruple bang would be clearer? :-P
j_random_hacker
+5  A: 
if (((value & 1 ? 1 : 0) +
     (value & 2 ? 1 : 0) +
     (value & 4 ? 1 : 0) +
     (value & 8 ? 1 : 0)) >=3)
Paul Beckingham
+21  A: 

Alternative solution: You can put all your numbers into a binary-coded lookup table:

int AtleastThreeBits (int a)
{
  return (0xe880>>(a&15))&1;
}

Each bit of the magic number represents an answer. In the constant 0xe880 bits 7,11,13,14 and 15 are set. You select the correct bit using a shift and mask it out.

It's not as readable as your solution but faster..

Nils Pipenbrinck
I don't normally upvote "clever" answers since I prefer readability but I'll give you one for cleverness this time - this may be handy for embedded systems.
paxdiablo
Very clever! +1.
j_random_hacker
Very clever indeed - I'm with paxdiablo on this one. I did a quick look at what MSVC in an optimized compile does to several of the answers here and this boils down to 4 instructions. The clear winner in size and almost certainly execution time. Just don't ask me to maintain more than a little bit of code like this, please.
Michael Burr
can someone explain this? In the constant 0xe880 bits 7,11,13,14 and 15 are set.
SuperString
@SuperString (and others): This is based on de Bruijn sequences -- like a lookup table where the elements overlap! Have a look here for more: http://supertech.csail.mit.edu/papers/debruijn.pdf
j_random_hacker
Thanks for the comments, guys. I'm an embedded engineer at heart, so I always come up with such answers :-)
Nils Pipenbrinck
Actually I jumped to a conclusion, this is not using a de Bruijn sequence... But it's a cool trick, and they are cool in a somewhat related way :)
j_random_hacker
The magic number will be shifted by the number represented by your nibble. For each combination with 3 bits (111=7; 1011=11; 1101=13; 1110=14; 1111=15) we set the bit in our number giving 11101 000 1000 0000=0xe880. It's a lookup table so small it fits in a 16bit variable.
tristopia
that is very cool!
vicatcu
+2  A: 

You could try a look-up table! Then you could change your threshold easily.

static int nibbleCounts[] = { 0, 1, 1, 2,
                              1, 2, 2, 3,
                              1, 2, 2, 3,
                              2, 3, 3, 4 };
if (nibbleCounts[value & 0xF] >= 3)
    puts ("Hello!");
dreamlax
+1 for the space/speed trade-off but I fixed it from '=>' to '>='.
paxdiablo
Of course, if you didn't want to make the threshold configurable, you could just lookup a true/false value for a small (possible) performance increase.
paxdiablo
Yes, you're quite right, a simple test is probably quicker than a compare.
dreamlax
@pax, I only just noticed you changed it to `static` too! Perhaps a `const` qualifier may make things even easier for the optimiser?
dreamlax
@dreamlax: const generally doesn't help with optimization, but since the `nibbleCounts` array isn't intended to be modified (and things would break if it were modified), it wouldn't hurt to make it `const` so someone is less likely to decide to add code later that happens to modify it for whatever reason.
Michael Burr
@Michael Burr: If the contents of an array are known to be constant, the optimiser could use a static precomputed jump table, but if the contents may differ it is forced to read the array every time.
dreamlax
@myself: Actually I'm not sure I understand what I'm talking about there . . .
dreamlax
+2  A: 

You can use the carry from an addition to "fill in" the 1st 0-bit "hole" in a number. We allow at most one of these in the bottom nibble, so combining the original value and the "filled-in" version with | will produce a bottom nibble with all 1-bits in this case:

if (((val | (val + 1)) & 15) == 15)

I think this has the fewest operations of any (lookup-table-free) solution so far -- no, actually Nils Pipenbrinck's clever "in-place lookup table" has even fewer!

j_random_hacker
This one is equally as clever as Nils Pipenbrinck's (in my opinion)! I like it.
dreamlax
can someone explain how this works?
SuperString
j_random_hacker
+1  A: 
int x = val & 0x0f;    // mask to keep only the interesting bits

switch (x) {
    case  7:  // 0b0111 ==  7
    case 11:  // 0b1011 == 11
    case 13:  // 0b1101 == 13
    case 14:  // 0b1110 == 14
    case 15:  // 0b1111 == 15
        // at least 3 bits are set
        // do whatever you need, like

        printf("asdjfkadscjas \n");
        break;
}

It's not particularly clever, but I think the next pinhead that comes along and looks at the code will have no problem figuring out what the intent is and whether or not it's correct. And that's a really big plus when that pinhead is me trying to figure out what the hell I did in that function last week.

Michael Burr
Some compilers warn about no `default` case when the warning settings a high enough, but this much nicer looking than a lengthy chained `if` statement.
dreamlax
If your compiler or coding standard wants or needs a default case, just drop it in. The biggest drawback to this in my opinion is that it can't be used in an expression directly. You'd need to go through the trouble of wrapping it in a function, which has a good chance of being more trouble than it's worth.
Michael Burr
A: 

Interesting tangent to this question - I think I know a sort of clever answer to the question "How many bits are set in this value"

#include <stdint.h>
#include <stdio.h>

uint8_t NumBitsSet(uint32_t value){
   uint8_t num_bits_set = 0;
   while(value != 0){
     value = value & (value-1);
     num_bits_set++;
   }

   return num_bits_set;
}

int main(int argc, char *argv[]){
  uint32_t value = 2147483648;
  printf("numbits set in %x = %d", value, NumBitsSet(value));
  return 0;
}

You can use this as a basis for determining if exactly one bit is set, though you have to make a special check for zero.

uint8_t exactly_one_bit_set = (value & (value-1)) == 0 ? 1 : 0;

The trick here is that if a value has one bit set then one less than that value will have all the bits below that bit set and that bit cleared. and-ing those two things together will be always be zero.

vicatcu