了解带移位的右移运算符
Understanding the right shift operator with bit shifting
我很难理解右移运算符。我理解左shift.Say我们有一个没有
int n = 11; which is 1011
现在如果我们左移它n << 1
结果是
int a = n << 1 ; so a = 10110; (simply add a 0 to the end)
这是有道理的
现在右移是我遇到困难的地方
int a = n >> 1
我认为答案是 01011
(在前面加一个 0),这又是 1011,而不是 101。我的问题是我们是如何丢失最后一个数字的。
更新:
我对此的推理可能是假设一个 int 是 8 位,在这种情况下我们将有
int8 n = 1011 => 即 00001011
所以当我们右移 1 它超过 8 位 int 1 所以最后一位被丢弃并且它变成
0000101 ?这个理解对吗?
1011
右移后为101
。 从 1011
.
中删除了最右边的位
111110101
右移 3 后得到 111110
,删除粗体位 111110101
看来你对轮班的工作方式有误解。
移位不会在零的左边或右边添加。你不能只加数字,只有这么多位。让我们取你的数字,十进制数 11.
int n = 11; which is 1011
这是真的,但只说了一半。看,数字在 CPU 中有固定大小。对于整数,那是 32 位,但为了更容易,让我们假设 8 位数字。你的 11 看起来像这样:
+-+-+-+-+-+-+-+-+
|0|0|0|0|1|0|1|1|
+-+-+-+-+-+-+-+-+
它有8位。总是。现在让我们左移 1:
+-+-+-+-+-+-+-+-+
0|0|0|0|1|0|1|1| |
+-+-+-+-+-+-+-+-+
移位后,第一位得到"shifted out"。没有 space 来存储那个位。另外,最后一位是"empty",我们不能存储"emptyness"。只有一个或零个。相反,我们 "shift in" 零。所以你最终得到
+-+-+-+-+-+-+-+-+
|0|0|0|1|0|1|1|0|
+-+-+-+-+-+-+-+-+
右移时相反。我们再次从 11 开始:
+-+-+-+-+-+-+-+-+
|0|0|0|0|1|0|1|1|
+-+-+-+-+-+-+-+-+
并右移 1:
+-+-+-+-+-+-+-+-+
| |0|0|0|0|1|0|1|1
+-+-+-+-+-+-+-+-+
同样,每一位都右移 1。左边有一个空位,如前所述,刚好变为零。在右边,那个被移出,没有 space 来存储它。它只是丢失了。我们的最终人数是:
+-+-+-+-+-+-+-+-+
|0|0|0|0|0|1|0|1|
+-+-+-+-+-+-+-+-+
以上适用于无符号数,也称为逻辑右移。在二进制补码系统中,对于有符号数,它使用所谓的 算术右移 ,它不是移入零位,而是移入符号位。 IE。如果数字为负数,则最高有效位为 1,则移入 1,否则移入 0。
有几种查看方式。
首先,整数数字类型(在 C、C++、Java、C# 中)具有固定的位数。所以 11 实际上是(假设罕见的 8 位 int 以提高可读性):
00001101 (8 digits)
左移一位
000011010 (9 digits?)
但是由于我们的整数只能管理 8 位,所以最左边的位脱落了。
00011010 (8 digits)
32 位整数也是如此:最左边的位脱落。
右移也一样:右边的位掉了。
如果原来是:
00011010 (8 digits)
然后在左边添加一个位创建一个 9 位值,这是不受支持的。而是加零把所有的位都往右推一位,最右边的位掉了,结果是
00001101 (8 digits)
另一种看待它的方式就像乘法和除法。在小数中,当我们乘以 10 时,会在右边加一个零。左移就像乘法,但对于二进制。当我们除以 10 时,我们删除最右边的数字并将其放入小数部分。对于正二进制和右移它是相同的,我们只是失去了分数。
请注意,对于负数,C++ 中的事情要复杂得多。例如,left shifting a negative is undefined
假设我们有一个数字(我们会让它变得简单,比如 00010000
)并且我们想要将它向左移动,它看起来像这样:
00010000 << 1 = 00100000
我们取了一个数,把1
space列中每一列的值放在它的左边(因为1是我们放在位移位的另一个操作数上的数).
到现在为止?好的。
现在,右移有什么作用?好吧,它做相反的事情它将列 x spaces 中每一列的值放在它的右边。例如:
00010000 >> 1 = 00001000
几个更高级的例子:
01010101 << 1 = 10101010
01010101 >> 1 = 00101010
11111111 << 2 = 11111100
11111111 >> 2 = 00111111
注意:位移位将切断任何移过数据边界的位,如 11111111
的示例中那样,任何超出的位移位后的边缘丢失。
您没有 "lose" 最后一位数字。您只是没有改变您认为自己的价值。
您从 n = 0b1011
开始。您将其向左移动一位 并将结果存储到 a
,而 n
保持不变。然后,您将 n
(仍然具有值 0b1011
)向右移动并得到 0b0101
.
如果您将 a
向右移动而不是 n
,您会看到预期的结果。
我很难理解右移运算符。我理解左shift.Say我们有一个没有
int n = 11; which is 1011
现在如果我们左移它n << 1
结果是
int a = n << 1 ; so a = 10110; (simply add a 0 to the end)
这是有道理的
现在右移是我遇到困难的地方
int a = n >> 1
我认为答案是 01011
(在前面加一个 0),这又是 1011,而不是 101。我的问题是我们是如何丢失最后一个数字的。
更新: 我对此的推理可能是假设一个 int 是 8 位,在这种情况下我们将有 int8 n = 1011 => 即 00001011 所以当我们右移 1 它超过 8 位 int 1 所以最后一位被丢弃并且它变成 0000101 ?这个理解对吗?
1011
右移后为101
。 从 1011
.
111110101
右移 3 后得到 111110
,删除粗体位 111110101
看来你对轮班的工作方式有误解。
移位不会在零的左边或右边添加。你不能只加数字,只有这么多位。让我们取你的数字,十进制数 11.
int n = 11; which is 1011
这是真的,但只说了一半。看,数字在 CPU 中有固定大小。对于整数,那是 32 位,但为了更容易,让我们假设 8 位数字。你的 11 看起来像这样:
+-+-+-+-+-+-+-+-+
|0|0|0|0|1|0|1|1|
+-+-+-+-+-+-+-+-+
它有8位。总是。现在让我们左移 1:
+-+-+-+-+-+-+-+-+
0|0|0|0|1|0|1|1| |
+-+-+-+-+-+-+-+-+
移位后,第一位得到"shifted out"。没有 space 来存储那个位。另外,最后一位是"empty",我们不能存储"emptyness"。只有一个或零个。相反,我们 "shift in" 零。所以你最终得到
+-+-+-+-+-+-+-+-+
|0|0|0|1|0|1|1|0|
+-+-+-+-+-+-+-+-+
右移时相反。我们再次从 11 开始:
+-+-+-+-+-+-+-+-+
|0|0|0|0|1|0|1|1|
+-+-+-+-+-+-+-+-+
并右移 1:
+-+-+-+-+-+-+-+-+
| |0|0|0|0|1|0|1|1
+-+-+-+-+-+-+-+-+
同样,每一位都右移 1。左边有一个空位,如前所述,刚好变为零。在右边,那个被移出,没有 space 来存储它。它只是丢失了。我们的最终人数是:
+-+-+-+-+-+-+-+-+
|0|0|0|0|0|1|0|1|
+-+-+-+-+-+-+-+-+
以上适用于无符号数,也称为逻辑右移。在二进制补码系统中,对于有符号数,它使用所谓的 算术右移 ,它不是移入零位,而是移入符号位。 IE。如果数字为负数,则最高有效位为 1,则移入 1,否则移入 0。
有几种查看方式。
首先,整数数字类型(在 C、C++、Java、C# 中)具有固定的位数。所以 11 实际上是(假设罕见的 8 位 int 以提高可读性):
00001101 (8 digits)
左移一位
000011010 (9 digits?)
但是由于我们的整数只能管理 8 位,所以最左边的位脱落了。
00011010 (8 digits)
32 位整数也是如此:最左边的位脱落。
右移也一样:右边的位掉了。 如果原来是:
00011010 (8 digits)
然后在左边添加一个位创建一个 9 位值,这是不受支持的。而是加零把所有的位都往右推一位,最右边的位掉了,结果是
00001101 (8 digits)
另一种看待它的方式就像乘法和除法。在小数中,当我们乘以 10 时,会在右边加一个零。左移就像乘法,但对于二进制。当我们除以 10 时,我们删除最右边的数字并将其放入小数部分。对于正二进制和右移它是相同的,我们只是失去了分数。
请注意,对于负数,C++ 中的事情要复杂得多。例如,left shifting a negative is undefined
假设我们有一个数字(我们会让它变得简单,比如 00010000
)并且我们想要将它向左移动,它看起来像这样:
00010000 << 1 = 00100000
我们取了一个数,把1
space列中每一列的值放在它的左边(因为1是我们放在位移位的另一个操作数上的数).
到现在为止?好的。
现在,右移有什么作用?好吧,它做相反的事情它将列 x spaces 中每一列的值放在它的右边。例如:
00010000 >> 1 = 00001000
几个更高级的例子:
01010101 << 1 = 10101010
01010101 >> 1 = 00101010
11111111 << 2 = 11111100
11111111 >> 2 = 00111111
注意:位移位将切断任何移过数据边界的位,如 11111111
的示例中那样,任何超出的位移位后的边缘丢失。
您没有 "lose" 最后一位数字。您只是没有改变您认为自己的价值。
您从 n = 0b1011
开始。您将其向左移动一位 并将结果存储到 a
,而 n
保持不变。然后,您将 n
(仍然具有值 0b1011
)向右移动并得到 0b0101
.
如果您将 a
向右移动而不是 n
,您会看到预期的结果。