当前位置: 首页 > 科技观察

当移位的位数为负时会发生什么?

时间:2023-03-15 14:58:52 科技观察

有编程经验的同学应该对shift操作不陌生。在日常工作中或多或少会有用处。当移位数为负数或移位数超过该类型的最大二进制数时,与正常的移位处理不同。下面将详细描述这两种情况。在此之前,先了解下正常的shift操作。正数的左移和正数的右移。左边空白的位置补0,右移表示二进制位右移,左边空白的位置补0(符号位为0)。左移左移运算,最高符号位会出现0或1,所以结果会出现正负数的情况,新建测试文件base.cpp,代码如下#include#includeusingnamespacestd;int32_tmain(int32_targc,char*argv[]){int32_ta=7;cout<<"(a<<2)="<<(a<<2)<#includeusingnamespacestd;int32_tmain(int32_targc,char*argv[]){int32_ta=7;cout<<"(a>>1)="<<(a>>1)<>31)="<<(a>>31)<>1)=3(a>>31)=0在上面的示例代码中,变量a的值为7,对应的二进制值为00000000000000000000000000000111右移1位:二进制右移1位,左边加0,多余的位舍去正确的。结果为00000000000000000000000000000011,对应的十进制数为3右移31位:二进制右移31位,左加31位0,舍去多余的31位二进制右移,结果为00000000000000000000000000000000,对应的十进制为0负数左移和右移负数左移都是二进制位向左移动,加0右边空位,将二进制位向右移动,左边空位加1(符号位为1)。这与正数不同。计算机使用补码以正数的形式进行各种运算。正数的补码就是它自己,负数的补码就是把它的正数取反,左边加1。负数向左移动。符号位可能会变成0,所以结果会出现正负数的情况,如果一直向左移动,最终会变成0。修改base.cpp文件,代码如下#include#include使用名称spacestd;int32_tmain(int32_targc,char*argv[]){int32_tb=-3;cout<<"(b<<1)="<<(b<<1)<#includeusingnamespacestd;int32_tmain(int32_targc,char*argv[]){int32_tb=-3;cout<<"(b>>1)="<<(b>>1)<>31)="<<(b>>31)<>1)=-2(b>>31)=-1上面代码中,变量b的值为-3,对应的二进制值为11111111111111111111111111111101右移1位:二进制位移至向右减1位,左边加1,多余的位从右边舍去在二进制中,结果为11111111111111111111111111111110,对应的十进制为-2。右移31位的过程如下。根据上图,从上图可以看出,最右边的31位是二进制1111111111111111111111111111110因为超过了最大位数,所以被丢弃了。把原来左边的1移到最右边,左边加了31位的1。最终结果为:11111111111111111111111111111111对应的十进制数-1移位位数超出最大类型当移位的位数大于等于数值类型的最大位数时,实际numberofshifteddigits为:移位的位数与该类型的最大位数取模运算,余数为要移位的位数。无论左移还是右移,这种方法都适用。例如:类型为int32_t,移位位数为34,实际移位位数为:34%32=1修改base.cpp文件,内容如下:#include#includeusingnamespacestd;int32_tmain(int32_targc,char*argv[]){int32_ta=7;cout<<"(a>>32)="<<(a>>32)<>33)="<<(a>>33)<>32)=7(a>>33)=3(a<<34)=28变量a的值为7,对应的二进制值为00000000000000000000000000000111右移32位bits:由于shift的位数等于int32_t的最大位数,所以实际移位的位数是32%32=0,右移0位表示不移位,所以结果还是7和右移33位:移位的位数大于int32_t的最大位数,所以实际移位的位数为33%32=1,右移1位,左加0,多余的舍弃右移位,结果为:00000000000000000000000000000011,对应十进制为3左移34位:shift如果位数大于32,则实际移位数为34%32=2,左移2位,右加0,舍去左边多余的位,结果为:00000000000000000000000000011100,对应的小数为28innormalconditions在此条件下,当移位次数相同时,多次移位操作的结果与一次移位操作的结果相同,例如:一个值为7的int32_t变量,7<<1<<2和7<<3结果是一样的。当移位数大于或等于最大位数时,上述结果不同。例如:一个值为7的int32_t变量,虽然7<<33和7<<20<<13都移位了33位,但是结果是不一样的。前者为14,后者为0。移位后的数字为负值。当移位数为负值时,实际移位数为:移位数类型的最大位数加上移位数。如果结果仍然为负数,则结果继续添加移位后的数值类型的最大位数,直到结果不为负数。这时候的结果就是最后的shift。位数例如:需要移位的数据类型为int32_t,移位数为-31,最终移位数为:32+(-31)=1当移位数为-60时,计算最终移位位数,32+(-60)=-28,由于结果还是负数,所以继续相加,32+(-28)=4,这次结果不为负数,所以最后移位位数为4修改base.cpp文件,内容如下:#include#includeusingnamespacestd;int32_tmain(int32_targc,char*argv[]){int32_ta=7;cout<<"(a>>-31)="<<(a>>-31)<>-60)<>-31)=3(a>>-60)=0变量a的值为7,对应的二进制为00000000000000000000000000000111右移-31位:移位个数为负数,实际右移32+(-31)=1位,结果为:00000000000000000000000000000011,对应十进制为3右移-60位:移位数为负数,实际右移为32+32+(-60)=4位,结果为:00000000000000000000000000000000,对应的十进制为0。总结本文主要介绍左移和右移操作。左移相当于乘以2的N次方,右移相当于除以2的N次方。需要注意的是,当移位的位数为负数或大于等于该类型的最大位数时,编译器对待它们的方式与正常的移位不同