K& R练习2.6位操作

时间:2014-08-15 09:19:36

标签: c

“写一个函数setbits(x,p,n,y)返回x,其中n位从位置p开始,设置为y的最右边n位,其他位保持不变。”

我无法弄清楚我做错了什么。

#include <stdio.h>
unsigned setbits(unsigned int x, int p, int n, unsigned y);

int main()
{
    unsigned x = 213;
    unsigned y = 121;
    int p = 4;
    int n = 4;

    x = setbits(x, p, n, y);
    printf("%u\n", x);

    getch();
    return 0;
}
unsigned setbits(unsigned x, int p, int n, unsigned y)
{
    return ((~(~0 << n) & y) << (p + 1 - n) | (~(~(~0 << n)) << (p + 1 - n) & x));
}

在纸面上,我得到了211,但是我的代码产生了210.K&amp; R答案簿算法也返回210.我无法弄清楚我在这里做错了什么。

编辑:以下是答案书中的代码:

unsigned setbits(unsigned x, int p, int n, unsigned y)
{
    return x & ~(~(~0 << n) << (p + 1 - n)) | (y & ~(~0 << n)) << (p + 1 - n);
}

重新编辑。在将代码分成不同的行时,我想通了。问题是最后一个x旁边的错误括号:

//original
{
    return ((~(~0 << n) & y) << (p + 1 - n) | (~(~(~0 << n)) << (p + 1 - n) & x));
}

//fixed
{
    return ((~(~0 << n) & y) << (p + 1 - n)) | (~(~(~0 << n) << (p + 1 - n)) & x);
}

这是破解的代码。这看起来还不错吗?我应该使用这样的变量:

int setbits(unsigned x, int p, int n, unsigned y)
{
    unsigned z, k;

    z = y & ~(~0 << n);
    z = z << (p + 1 - n);
    k = ~((~(~0 << n)) << (p + 1 - n));
    k = k & x;

    return z | k;
}

3 个答案:

答案 0 :(得分:0)

措辞有点难以理解,但我认为这就是它所要求的:

<击>

<击>
unsigned setbits(unsigned int x, int p, int n, unsigned y){
  return x | ((y&((1<<n)-1))<<(p-n));
}

<击>

unsigned setbits(unsigned int x, int p, int n, unsigned y){
  return (x & ~(((1<<n)-1)<<(p-n))) | ((y&((1<<n)-1))<<(p-n));
}

击穿:

  • 左半边的

    • ((1<<n)-1)将向左移1 n位,减1使所有位向右移1。
    • <<(p-n)将它们左移p-n
    • ~将这些位置为0,其他所有位置为1s
    • x &并将其x转换为0。
  • |

    的右半部分
    • ((1<<n)-1)与上述相同
    • y &将仅屏蔽那些位
    • <<(p-n)会将这些位p-n移到左侧
    • left | right将值组合在一起,以便:
      • 从位置n开始的p位设置为n的最右侧y位,而x的其他位保持不变

答案 1 :(得分:0)

书中的解决方案

unsigned setbits(unsigned x, int p, int n, unsigned y)
{
    return x & ~(~(~0 << n) << (p + 1 - n)) | (y & ~(~0 << n)) << (p + 1 - n);
}

p=4

x组件

l1 = ~0 => 1111_1111_1111_1111_1111_1111_1111_1111
l2 = l1 << n => 1111_1111_1111_1111_1111_1111_1111_0000
l3 = ~(l2) => 0000_0000_0000_0000_0000_0000_0000_1111
l4 = (p + 1 - n) => 1
l5 = (l3) << (l4) => 0000_0000_0000_0000_0000_0000_0001_1110
l6 = ~l5 => 1111_1111_1111_1111_1111_1111_1110_0001
l7 = x & l6 => xxxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxx0_000x

y组件

s1 = ~0 => 1111_1111_1111_1111_1111_1111_1111_1111
s2 = s1 << n => 1111_1111_1111_1111_1111_1111_1111_0000
s3 = ~s2 => 0000_0000_0000_0000_0000_0000_0000_1111
s4 = (p + 1 - n) => 1
s5 = s3 << s4 => 0000_0000_0000_0000_0000_0000_0001_1110
s6 = y & s5 => 0000_0000_0000_0000_0000_0000_000y_yyy0

o = l7 | s6

输出

xxxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxy_yyyx
^all these uncounted bits!!!^ .

  

编写一个函数setbits(x,p,n,y),该函数返回x,其中n位从位置p开始的n位设置为最右 ,其他位保持不变。

我们是否从零开始从右边开始计数,然后到达位置p时开始从右边的n位开始计数?

unsigned类型为int,可以通过

进行验证

$ gcc -o ansi-c_2-6 *.c -std=c89
$ ansi-c_2-6

#include <stdio.h>
int main() {
  printf("%s", (sizeof(unsigned) == sizeof(int)) ? "TRUE" : "FALSE");
  return 0;
}

结论

解决方案书有误。

解决方案

注释

  • bits = CHAR_BIT * sizeof( 数据类型 ))
  • 右移带有最高有效位。 INT_MIN >> 31 == ~0
  • if p + n > 32,您可以放弃,但很快就会失去控制

x的东西

左侧

left_mask = INT_MIN >> (p - 1)

右侧

right_mask = INT_MAX >> (p - 1 + n)

x = x & (left_mask | right_mask)

y的东西

中间

mid_mask = ~(left_mask | right_mask)

y = (y << (bits - p - n)) & mid_mask

return的东西

x | y

TL; DR

书有误

改为执行此操作

unsigned setbits(unsigned x, unsigned char p, unsigned char n, unsigned y)
{
  char bits = CHAR_BIT * sizeof(unsigned);
  unsigned left_mask, right_mask, mid_mask;
  left_mask = p > 0 ? INT_MIN >> (p-1) : 0;
  right_mask = INT_MAX >> (p - 1 + n);
  mid_mask = (left_mask | right_mask) & x;
  x = (left_mask | right_mask) & x;
  y = y << (bits - p - n) & mid_mask;
  return x | y;
}

限制:

  • n > 0
  • p + n < sizeof(unsigned) * CHAR_BIT

答案 2 :(得分:-1)

unsigned setbits(unsigned x, int p, int n, int y) {
   return x | (~(~0 << n) << p);
}
相关问题