C语言 K&R运动2.6位微操纵

holgip5t  于 2023-03-22  发布在  其他
关注(0)|答案(3)|浏览(102)

编写一个函数setbits(x,p,n,y),它返回x,其中从位置p开始的n位设置为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&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;
}
l5tcr1uw

l5tcr1uw1#

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

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,其他位均为1
  • x &和它到x以将这些位变为0。
  • 右半边|
  • ((1<<n)-1)同上
  • y &将仅屏蔽这些位
  • <<(p-n)将把这些位p-n向左移位
  • left | right将对这些值进行OR运算,从而:
  • 从位置p开始的n位被设置为y的最右边的n位,而x的其他位不变
gk7wooem

gk7wooem2#

unsigned setbits(unsigned x, int p, int n, int y) {
   return x | (~(~0 << n) << p);
}
qrjkbowd

qrjkbowd3#

书中解决方案

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
x1米11米1x
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,其中从位置p开始的n位被设置为y的 * 最右*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东东

左侧

x1米30英寸1x

右侧

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
  • x1米39英寸

相关问题