为什么-1>> 1是-1?并且1>> 1是0!

时间:2010-11-29 21:53:27

标签: c++

我有下一个代码:

std::cout << (-10 >> 1) << std::endl;
std::cout << (-9 >> 1) << std::endl;
std::cout << (-8 >> 1) << std::endl;
std::cout << (-7 >> 1) << std::endl;
std::cout << (-6 >> 1) << std::endl;
std::cout << (-5 >> 1) << std::endl;
std::cout << (-4 >> 1) << std::endl;
std::cout << (-3 >> 1) << std::endl;
std::cout << (-2 >> 1) << std::endl;
std::cout << (-1 >> 1) << std::endl;

结果是:

-5
-5
-4
-4
-3
-3
-2
-2
-1
-1

但为什么呢?

-11111 1111(1个字节),-1 >> 1必须为:1011 1111且不是-10! (符号位没有移位,我知道)

有人可以向我解释这是如何运作的吗?

4 个答案:

答案 0 :(得分:24)

标准5.8 / 3(轮班操作员):

  

E1的值&gt;&gt; E2是E1   右移E2位位置。如果E1   有一个无符号类型或E1有一个   签名类型和非负值,   结果的值是   E1的商的组成部分   除以提高的数量2   权力E2。 如果E1有签名类型   由此产生的负值   值是实现定义的。

所以对于“为什么?”这个问题,标准答案是:为什么不呢。

答案 1 :(得分:17)

对负数进行右移是实现定义的。

将符号扩展位移到最左边位的实现按照您的报告工作。

至于为什么这样做,这是因为右移可以用2除以圆的朝向负无穷大(例如像floor())舍入行为来划分:

(-8 >> 2) == -2
(-9 >> 2) == -3
(-10 >> 2) == -3
(-11 >> 2) == -3
(-12 >> 2) == -3

See this SO question.

答案 2 :(得分:3)

  

-1&gt;&gt; 1必须是:1011 1111

如果是真的,-10&gt;&gt;在2的补码中,1将是10111011 == -69。不是一个非常有用的结果!

虽然语言行为未定义(因此结果,有用或无法依赖),常见行为(以及本案例中展示的行为)是执行“符号扩展”。

符号位未移位”, 移位,并且空位被填充等于符号位的值。这种行为既保留了符号,又提供了除了-1之外的所有值都观察到的“预期的”二分频操作。对于负值,-1是右移的“终值”,因为零是正数。也就是说,负数的右移倾向于-1,正数趋于零。

答案 3 :(得分:3)

通常,右移定义为实现为“算术”或“逻辑”。不同之处在于,对于逻辑右移,最左侧的位始终设置为零。使用算术右移,最左边的位是前一个值的副本。

例如,让我们假装值只有8位,以便更容易跟踪。然后:

逻辑:

0111 1111 >> 1 = 0011 1111
1111 1111 >> 1 = 0111 1111
1111 1110 >> 1 = 0111 1111

算术:

0111 1111 >> 1 = 0011 1111
1111 1111 >> 1 = 1111 1111
1111 1110 >> 1 = 1111 1111

算术右移相当于除以2并向负无穷大舍入。

在C ++中,右移运算符是逻辑运算符还是算术运算符是特定于实现的。也就是说,每个编译器编写者都可以自己决定,可能是根据他正在进行的计算机体系结构更容易做的事情。

您的符号位未移位的说法不正确。符号位的移位与所有其他位一样。唯一的问题是取代它的原因。

Java有两个不同的右移运算符:&gt;&gt;是算术和&gt;&gt;&gt;是合乎逻辑的。