按位和C编程

cok*_*ude 4 c

我可以请一些帮助理解一下,如果是速记吗?我评论了我的想法.

//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':' ');

-----------------------------------------------
Run Code Online (Sandbox Code Playgroud)

我想出了这一个.

    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);

}
Run Code Online (Sandbox Code Playgroud)

产量

XX X 
Run Code Online (Sandbox Code Playgroud)

成功putchar返回的原因1. http://www.cplusplus.com/reference/cstdio/putchar/

Eri*_*ert 51

不确定这个.有人可以解释一下吗?

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

不要问鱼,问怎么钓鱼.不要向你解释,让我教你如何向自己解释.

我现在不理解这个疯狂的代码,所以我将写下我将用来理解这段代码的过程.

我们首先通过重新格式化它来开始理解它,以便缩进为我们提供线索:

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

好的,那不是更好.让我们通过引入两个解释变量来尝试理解它.

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

那还不是很清楚.让我们试着通过将条件表达式转换为条件语句来解决它.

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;
Run Code Online (Sandbox Code Playgroud)

还不是很清楚,但是现在我们可以注意到"if"语句的结构很奇怪:我们有两个可能的结果,其中一个必须满足所有三个条件,那么我们为什么要嵌套if语句呢?改写.

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

好的,我们现在变得更加简单了.让我们考虑这三个条件.是什么

(original ^ 34) && ...
Run Code Online (Sandbox Code Playgroud)

意思?那么,当且仅当结果不为零时,条件才会被认为是真的,所以让我们再引入三个解释变量并明确说明.

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;
Run Code Online (Sandbox Code Playgroud)

好了,现在让我们来问自己"是什么(x ^ y) != 0,甚至什么意思?在什么情况下可以在此是假的?只有x^y为零.在什么情况下可以x^y为零是真的吗?只有xy所有同位在什么情况下可以xy都位相同?只有它们相等.所以当且仅当操作数相等时条件为假,因此当且仅当它们不相等时才为真.所以我们可以将其重写为:

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;
Run Code Online (Sandbox Code Playgroud)

现在我们到了某个地方.现在让我们来看看上面的动作吧board[i].如果result为零则original|result则为无操作.唯一的另一种可能性就是result16.所以让我们再次重写,这次要消除 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;
Run Code Online (Sandbox Code Playgroud)

现在让我们注意到我们可以反转if并消除"无所事事"的情况:

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

现在我们可以使用这个事实

!(a && b)
Run Code Online (Sandbox Code Playgroud)

是一样的

!a || !b
Run Code Online (Sandbox Code Playgroud)

所以:

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

但是现在我们正在反转一个看似愚蠢的不平等.将它们变为等于并消除反转.

int original = board[i];
int condition34 = (original == 34);
int condition35 = (original == 35);
int condition3 = (original == 3);
if (condition34 || condition35 || condition3)
   board[i] = original | 16;
Run Code Online (Sandbox Code Playgroud)

现在让我们再次消除解释变量:

if ((board[i] == 34) || (board[i] == 35) || (board[i] == 3))
   board[i] |= 16;
Run Code Online (Sandbox Code Playgroud)

你去吧 现在我们以一种可以理解的形式获得程序片段.如果电路板位置为34,35或3,则设置16位,否则不执行任何操作.

我不知道为什么有人会想要编写原始程序片段,因为我所展示的方式更加清晰,但有时候人们编写奇怪的代码.

这就是当您遇到无法理解的代码时所执行的操作:将其重写为您可以理解的完全等效的代码.通过将子表达式提取为解释变量来简化复杂表达式是一种很好的技术.

  • @cokedude:这很不幸.我注意到,就非空白字符而言,我的解决方案实际上比原始解决方案*更短*,并且具有人类可以理解的好处.此外,除非您正在玩Code Golf,否则较短的程序绝不是更好的程序. (8认同)