练习是: 写一个函数setbits(x,p,n,y)返回x,其中n位从位置p开始,设置为y的最右边n位,其他位保持不变。
我尝试解决方案是:
#include <stdio.h>
unsigned setbits(unsigned, int, int, unsigned);
int main(void)
{
printf("%u\n", setbits(256, 4, 2, 255));
return 0;
}
unsigned setbits(unsigned x, int p, int n, unsigned y)
{
return (x >> (p + 1 - n)) | (1 << (n & y));
}
这可能不正确,但我在正确的道路上吗?如果没有,我做错了什么?我不确定为什么我不完全理解这一点,但我花了大约一个小时试图想出这个。
感谢。
答案 0 :(得分:5)
这是你的算法:
mask
。mask2
。And
x与mask2的反转。 And
y带面具,左移p次。Or
这两个操作的结果,并返回该值。答案 1 :(得分:2)
我认为答案是对2.9节中的getbits示例稍加修改的应用程序。
让我们按如下方式分解:
Let bitstring x be 1 0 1 1 0 0
Let bitstring y be 1 0 1 1 1 1
positions -------->5 4 3 2 1 0
设置p = 4 and n =3
为我们提供了来自x的位串0 1 1
。它从4开始,到2结束,跨越3个元素。
我们想要做的是将0 1 1
替换为1 1 1
(位串y的最后三个元素)。
让我们暂时忘记左移/右移并按如下方式显示问题:
我们需要从位串y中获取最后三位数,即1 1 1
将1 1 1
直接放在bitstring x的4 3 and 2
位置下。
将0 1 1
替换为1 1 1
,同时保持其余位完整...
现在让我们进一步了解一下......
我的第一个陈述是:
We need to grab the last three digits from bitstring y which is 1 1 1
从位串中隔离位的方法是首先从具有全0的位串开始。
我们最终得到0 0 0 0 0 0
。
0s有这个令人难以置信的属性,其中按位'和'使用另一个数字给我们所有的0和按位'|'用另一个数字给我们回到那个其他数字。
0本身在这里没有用......但它告诉我们如果我们'|' y的最后三位数字为'0',我们最终会得到1 1 1. y中的其他位在这里并不关心我们,因此我们需要找出一种方法来将这些数字归零,同时保持最后三位完整。实质上我们需要数字0 0 0 1 1 1
。
让我们看一下所需的一系列转换:
Start with -> 0 0 0 0 0 0
apply ~0 -> 1 1 1 1 1 1
lshift by 3 -> 1 1 1 0 0 0
apply ~ -> 0 0 0 1 1 1
& with y -> 0 0 0 1 1 1 & 1 0 1 1 1 1 -> 0 0 0 1 1 1
这样我们就可以将最后三位用于设置......
我的第二个陈述是:
将1 1 1直接置于位串x 4的位置4 3和2之下。
可以在第2.9节的getbits示例中找到执行此操作的提示。我们对位置4,3和2的了解可以从值p = 4 and n =3
中找到。 p是位置,n是bitset的长度。结果p+1-n
给出了最右边位的位集偏移量。在此特定示例中p+1-n = 4 +1-3 = 2
。
所以..如果我们在字符串0 0 0 1 1 1
上左移2,我们最终得到0 1 1 1 0 0
。如果您将此字符串放在x下,您会注意到1 1 1
与x的位置4 3 and 2
对齐。
我想我终于到了某个地方......我做的最后一句话是......
将0 1 1替换为1 1 1,同时保持其余位完整...
让我们现在回顾一下我们的字符串:
x -> 1 0 1 1 0 0
isolated y -> 0 1 1 1 0 0
按位或按这两个值给出了我们在这种情况下所需的内容:
1 1 1 1 0 0
但是如果不是1 1 1
而是1 0 1
,我们就会x -> bit by bit...1(stays) 0(changes) 1(changes) 1(changes) 0(stays) 0(stays)
失败,所以如果我们需要多挖一点来获得我们的“银弹”......
让我们再看一下上面两个字符串......
1 x x x 0 0
理想情况下......我们需要位串Bitwise complement of isolated y -> 1 0 0 0 1 1
& this with x gives us -> 1 0 0 0 0 0
| this with isolated y -> 1 1 1 1 0 0 (TADA!)
,其中x将与1交换。
这是一个有助于我们的直觉的飞跃......
{{1}}
希望这篇长篇文章能帮助人们理解并解决这些比特掩码问题...
谢谢
答案 2 :(得分:0)
请注意,~0 << i
会为您提供一个数字,其最低有效i
位设置为0
,其余位设置为1
。同样,~(~0 << i)
会为您提供一个数字,其中最不重要的i
位设置为1
,其余位设置为0
。
现在,要解决您的问题:
n
位以外的所有位(位于p
的位置设置为x
的位。为此,除了从位置1
开始的n
位之外,您需要一个除p
之外的掩码:
p+1
的位开始。p+1-n
位。&
此面具的x
会在步骤1中为您提供所需的数字。n
位y
位p+1-n
的数字,向左移位n
位。
&
位的掩码,并y
将其设置为y
以提取n
最不重要的{{1}比特。p+1-n
位。|
)步骤2和3.2的结果来获取您的号码。清除泥土? : - )
(上述方法应该与数字的大小无关,我认为这很重要。)
编辑:查看您的工作:n & y
对n
位没有任何作用。例如,如果n
为8,则需要y
的最后8位,但n & y
将选择y
的第4位(二进制中的8为1000) 。所以你知道这不可能是正确的。类似地,右移x
p+1-n
次为您提供一个数字,其中最重要的p+1-n
位设置为零,其余位由{{的最高位组成。 1}}。这不是你想要的。