Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

bitwise And C programming

Tags:

c

Can I please have some help understanding some bitwise and, and if shorthand? I put comments on what I thought it is.

//Bitwise AND not sure how it decides 32 or 0, then set board[i]    
board[i] = (randNum & 1024) ? 32 : 0;

//it the j variable j in the neighborOffset array, then mods it by 2048
//then takes that variable from the board array, then shifts 1 to 32
//then bitwise and of those 2 variables.
if(board[(i + neighborOffset[j]) % 2048] & (1 << 5))

//Not sure about this one. Can someone please explain it? 
board[i] |= ((board[i] ^ 34) && (board[i] ^ 35)) ? ( (board[i]^3) ? 0 : (1<<4)) : (1<<4);

//Not sure how it decides if it uses 'X' or ' '
putchar(board[i] ? 'X':' ');

-----------------------------------------------

I figured out this one.

    putchar(board[i] ? 'X':' ');

#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <signal.h>
#include <stdlib.h>
//#include <dos.h>


int main()
{
    int board[2048] = {0};
    board[0] = 5;
    board[1] = 9;
    board[2] = 0;
    board[3] = 2;

    putchar(board[0] ? 'X':' ');
    putchar(board[1] ? 'X':' ');
    putchar(board[2] ? 'X':' ');
    putchar(board[3] ? 'X':' ');
    printf(" \n");
    return (0);

}

Output

XX X 

The reason on success putchar returns 1. http://www.cplusplus.com/reference/cstdio/putchar/

like image 992
cokedude Avatar asked Nov 26 '22 21:11

cokedude


1 Answers

Not sure about this one. Can someone please explain it?

board[i] |= ((board[i] ^ 34) && (board[i] ^ 35)) ? ( (board[i]^3) ? 0 : (1<<4)) : (1<<4);

Don't ask for a fish, ask how to catch fish. Instead of explaining this to you, let me teach you how to explain it to yourself.

I don't understand this crazy code any more than you do right now, so I'm going to write down the process that I would use to understand this code.

We begin to understand it by first reformatting it so that indentation gives us a clue:

board[i] |= 
    ((board[i] ^ 34) && (board[i] ^ 35)) ? 
        ((board[i]^3) ? 
            0 : 
            (1<<4)) : 
        (1<<4);

OK, that's not much better. Let's try to understand it by introducing two explanatory variables.

int original = board[i];
int result =  
    ((original ^ 34) && (original ^ 35)) ? 
        ((original ^ 3) ? 
            0 : 
            (1<<4)) : 
        (1<<4);
board[i] = original | result;

That's still not very clear. Let's try to undestand it by turning conditional expressions into conditional statements.

int original = board[i];
int result;
if ((original ^ 34) && (original ^ 35))
{
    if (original ^ 3)
        result = 0;
    else
        result = 1 << 4;
}
else
    result = 1 << 4;

board[i] = original | result;

Still not very clear, but now we can notice that the structure of the "if" statements is bizarre: we have two possible results, and in one of them all three conditions must be met, so why do we have nested if statements at all? Rewrite.

int original = board[i];
int result;
if ((original ^ 34) && (original ^ 35) && (original ^ 3))
    result = 0;
else
    result = 1 << 4;
board[i] = original | result;

OK, we're getting a lot simpler now. Let's think about those three conditions. What does

(original ^ 34) && ...

mean? Well, the condition will be considered to be true if and only if the result is not zero, so let's introduce three more explanatory variables and make that clear.

int original = board[i];
int result;
int condition34 = (original ^ 34) != 0;
int condition35 = (original ^ 35) != 0;
int condition3 = (original ^ 3) != 0;
if (condition34 && condition35 && condition3)
    result = 0;
else
    result = 1 << 4;
board[i] = original | result;

OK, now let's ask ourselves "what does (x ^ y) != 0 even mean? Under what circumstances can this be false? Only if x^y is zero. Under what circumstances can x^y being zero be true? Only if x and y have all the same bits. Under what circumstances can x and y have all bits the same? Only if they are equal. So the condition is false if and only if the operands are equal, and therefore it is true if and only if they are unequal. So we can rewrite this as:

int original = board[i];
int result;
int condition34 = (original != 34);
int condition35 = (original != 35);
int condition3 = (original != 3);
if (condition34 && condition35 && condition3)
    result = 0;
else
    result = 1 << 4;
board[i] = original | result;

Now we are getting somewhere. Now let's look at the action on board[i]. If result is zero then original|result is a no-op. The only other possibility is that result is 16. So let's rewrite this again, this time to eliminate result:

int original = board[i];
int condition34 = (original != 34);
int condition35 = (original != 35);
int condition3 = (original != 3);
if (condition34 && condition35 && condition3)
{ /* do nothing */ }
else
   board[i] = original | 16;

Now let's notice that we can invert the if and eliminate the "do nothing" case:

int original = board[i];
int condition34 = (original != 34);
int condition35 = (original != 35);
int condition3 = (original != 3);
if (!(condition34 && condition35 && condition3))
   board[i] = original | 16;

Now we can use the fact that

!(a && b)

is the same thing as

!a || !b

So:

int original = board[i];
int condition34 = (original != 34);
int condition35 = (original != 35);
int condition3 = (original != 3);
if ((!condition34) || (!condition35) || (!condition3))
   board[i] = original | 16;

But now we are inverting a not-equals, which seems silly. Turn them into equals and eliminate the inversion.

int original = board[i];
int condition34 = (original == 34);
int condition35 = (original == 35);
int condition3 = (original == 3);
if (condition34 || condition35 || condition3)
   board[i] = original | 16;

Now let's eliminate the explanatory variables again:

if ((board[i] == 34) || (board[i] == 35) || (board[i] == 3))
   board[i] |= 16;

And there you go. Now we have the program fragment in a form that can be understood. If the board position is 34, 35 or 3, then set the 16 bit, otherwise, do nothing.

I have no idea why someone would want to write the original program fragment when the way I've shown is so much more clear, but sometimes people write strange code.

This is what you do when you encounter code you can't make sense of: rewrite it into exactly equivalent code that you can make sense of. Simplifying complex expressions by extracting sub-expressions into explanatory variables is a great technique for that.

like image 51
Eric Lippert Avatar answered Jan 17 '23 16:01

Eric Lippert