移位运算符的效果

Posted fy_闷油瓶

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了移位运算符的效果相关的知识,希望对你有一定的参考价值。

目录

移位运算符介绍

以C语言为例,在C语言中移位运算符是指将二进制位向左或者向右移动n位,其操作数必须为整型。左移运算符:<< ;右移运算符:>>

一、左移运算符

1.1左移运算规则

左移运算符将运算对象每一位二进制的值向左移动指定的位数,左末端的值丢失,右侧补0。
例如:-5用二进制表示为
10000000 00000000 00000000 00000101(原码)
11111111 11111111 11111111 11111011 (补码)
左移1位后等于-10:
11111111 11111111 11111111 11110110(补码)
10000000 00000000 00000000 00001010(原码)

1.2左移的运算效果

首先我们看一段代码:

#include<stdio.h>
int main()

	int a = 2, b = -2;
	a = a << 1;
	b = b << 1;
	printf("a=%d,b=%d", a, b);
	return 0;

程序最后运行的结果为:
我们可以看到,左移移位后,相当于在原来的基础上乘2,这是巧合么还是必然呢?

对于正数而言,转换成二进制后,第n位的权重为 2^ (n-1), 当左移一位后,原本的第n位到了n+1位,权重变成了 2^n,所以左移一位相当于乘2。对于负数,同样的道理,左移一位也相当于乘2。哪怕是超过了整型范围,其结果也相当于乘2。
例如:

#include<stdio.h>
int main()

	int a = 1073741825;
	int c = 2 * a;
	int b = a << 1;
	printf("%d\\n", b);
	printf("%d\\n", c);
	return 0;

#include<stdio.h>
int main()

	int a = -1073741825;
	int c = 2 * a;
	int b = a << 1;
	printf("%d\\n", b);
	printf("%d\\n", c);
	return 0;

二、右移运算符

2.1右移运算规则

右移1位,将当前操作数的所有二进制位向右移动一位。对于无符号类型,左侧补0;对于有符号类型,其结果取决于机器。左侧可以补0,也可以补1。(算数右移左侧补符号位,逻辑右移左侧补0)VS2019中遵循算数右移规则,因此我们对算数右移进行分析。

例如:5用二进制表示为
00000000 00000000 00000000 00000101
左移1位后等于2:
00000000 00000000 00000000 00000010
-5用二进制表示为
10000000 00000000 00000000 00000101(原码)
11111111 11111111 11111111 11111011 (补码)
左移1位后等于-3:
11111111 11111111 11111111 11111101(补码)
10000000 00000000 00000000 00000011(原码)

2.2 右移的运算效果

正数

右移1位原本第n位将被移到第n-1位,权重将会由2^(n-1)变为 2^(n-2),因此相当于除以2

负数

当N为奇数时:
符号位为1,最低为也为1
1××××××× ×××××××× ×××××××× ×××××××1(原码)
1******* ******** ******** *******1(补码)
其中 * 表示×取反后的结果
右移1位后变成
11 ****** ******** ******** ********(补码)
10×××××× ×××××××× ×××××××× ×××××××(×+1)(原码)
将原码换种方式表示
10×××××× ×××××××× ×××××××× ×××××××× +1
由于符号位是负,因此在最后一位上加上1,相当于加上
10000000 00000000 00000000 00000001(即-1)因此相当于将原来的数减去1,可以看见,在减1之前,相当于原来的原码,每一位的权重变为了原来的1/2,因此当N为基数时,右移1位相当于除以2再减1,即N=N/2-1。
因为N为基数,所以 N/2 - 1 =(N-1) /2。

当N为偶数时,符号位为1,最低为为0
1××××××× ×××××××× ×××××××× ×××××××0(原码)
1******* ******** ******** ******* 1(反码)
1******* ******** ******** ******( *+1)0(补码) 最后1位1加上1会向高位进1,我们表示为 *+1
当N向右移动1位后变成

11****** ******** ******** ******( *+1) (补码)
10×××××× ×××××××× ×××××××× ××××××××(原码)
这里由补码求原码的时候,我们用原码=(补码-1)取反,就可以把( *+1)的1处理掉,从而得到
10×××××× ×××××××× ×××××××× ××××××××,和移位前相比,每位的权重变为了原来的1/2,因此N为偶数时,右移1位,相当于除以2,即N=N/2。
因为N为偶数,所以N/2 = (N-1)/2。
当操作数为负时,左移一位相当于(N-1)/2。

以上是关于移位运算符的效果的主要内容,如果未能解决你的问题,请参考以下文章

java移位运算

读《程序是怎样跑起来的》第二章有感

java的移位和异或运算

java中的无符号移位运算

一篇文章搞懂移位运算

Java移位运算之算术右移位