一次搞懂:正数 负数 左移<< 右移>> 移位运算规则 移位后的空位添补规则

一次搞懂:正数 负数 左移<< 右移>> 移位运算规则 移位后的空位添补规则

左移运算符 << :把一个数的所有位都向左移动若干位

int i = 1;

i = i << 2; //把i里的值左移2位

为了理解方便,假设 int 占1个字节(8位,实际32位机器占4字节,32位)

i = 0000 0100

i = i << 2 ;

//结果 i = 0001 0000

此时需要注意的是 int 类型 最左端的符号位

0 表示 正

1 表示 负

i = 0100 0000 //十进制为64 111 1111:127 1000 0000:128

i = i << 1 ; //变为i = 1000 0000 即十进制为-128 变成了最小数

这里是不是一脸问号???接下来解释为什么

计算机中以补码的形式存储数据

/*

正数补码 = 原码

负数补码 = 原码取反+1

*/

-1 原码为1000 0000 0000 0000 0000 0000 0000 0001

-1 反码为1111 1111 1111 1111 1111 1111 1111 1110

-1 补码为1111 1111 1111 1111 1111 1111 1111 1111

所以最小的负数是-2147483647吗?错,不是。

在二进制中,0有两种表方法。

+0 原码为0000 0000 0000 0000 0000 0000 0000 0000

-0 原码为1000 0000 0000 0000 0000 0000 0000 0000

因为0 只需要一个,所以把-0拿来当做一个最小的数-2147483648

这也就是为什么负数比正数多一个的原因(int 范围-2^31 ~ 2^31-1)

-2147483648 的补码表示为1000 0000 0000 0000 0000 0000 0000 0000 在32位没有原码

注意,这个补码并不是真正的补码,真正的补码是1 1000 0000 0000 0000 0000 0000 0000 0000 溢出

所以在这里只占1个字节带符号的int的最小值为-128 即 0100 0000 << 1 = 1000 0000 (即-128)

当左移的位数超过该数值类型的最大位数时,编译器会用左移的位数去模类型的最大位数,然后按余数进行移位,如:

int i = 1 //设int占1个字节,即8位 i = 1:0000 0001

i = i << 9;

// 9 % 8 = 1 即此时左移1位 i = 2 :0000 0010

int i = 64 //设int占1个字节,即8位 i = 1:0100 0000

i = i << 9;

// 9 % 8 = 1 即此时左移1位 i = 0 :1000 0000 最高位被丢弃

总结:丢弃高位,0补低位

右移运算符 >> :把一个数的所有位都向左移动若干位

符号位向右移动后,正数补0,负数补1,也就是汇编语言中的算术右移,同样当移动的位数超过类型的长度时,会取余数,余数是几,移动几位

整型 int 为4个字节32位,那么当我们右移32位会发生什么?35位呢?

原数: 2147483647 (整型最大值)

二进制: 01111111 11111111 11111111 11111111

结果不变

这是因为位移是一个取模的过程

当我们右移4位:4 % 32 = 4

当我们右移32位:32 % 32 = 0 也就是不动

那么当右移33位,那不就是右移1位吗!

无符号右移(没有无符号左移)

无符号右移在右移时,高位补0,也就是不会管你是不是负数

-10 >>> 1

二进制: 01111111 11111111 11111111 11111011 | 0

是这样吗?答案是对的,负数无符号右移,高位同样补0

无符号右移1位后最高位的1变为了0,负数变为了正数

总结

负数右移高位补1

无符号负数高位补0

eg 小测验:

原数: 75

二进制: 00000000 00000000 00000000 01001011

请问 左移25位结果是?

10010110 00000000 00000000 00000000

-1778384896

总结

码制添补代码正数原码、补码、反码0负数原码0补码左移添0右移添1反码1

相关资讯