原码、补码以及正数/负数的左移和右移

原码、补码以及正数/负数的左移和右移文章目录一 原码和补码 1 1 原码表示法 1 2 补码表示法二 C 正数 负数的左移和右移 2 1 正数的左移和右移 2 2 负数的左移和右移 2 3 扩展 对正负数都适用 下面以正数为例 一 原码和补码对数据用 n 位二进制数编码后 机器数 X 表示为 X XnXn 1Xn 2 X2X1X X nX n 1 X n 2 X 2 X 1 X Xn Xn 1 Xn 2 X2 X1

一 、原码和补码

对数据用n位二进制数编码后,机器数X表示为: X = X n X n − 1 X n − 2 . . . X 2 X 1 X=X_nX_{n-1}X_{n-2}…X_{2}X_{1} X=XnXn1Xn2...X2X1

1.1 原码表示法

1)原码的定义:一个数的原码表示由符号位直接后跟数值位构成,因此,也称“符号-数值 (sign and magnitude)“表示法。原码表示法中,正数和负数的编码表示仅符号位不同,数值部分完全相同。

2)原码编码规则如下:

  • 当X为正数时, X n = 0 X_n=0 Xn=0,后面的位数表示数值。
  • 当X为负数时, X n = 1 X_n=1 Xn=1,后面的位数表示数值。

3)原码0有两种表示形式:

  • [ + 0 ] 原 = 000 … 0 [+0]_原 = 000…0 [+0]=0000
  • [ − 0 ] 原 = 100 … 0 [-0]_原=100…0 [0]=1000

4)原码表示范围(对于n位二进制编码): − ( 2 n − 1 − 1 ) -(2^{n-1}-1) (2n11) ( 2 n − 1 − 1 ) (2^{n-1}-1) (2n11)

1.2 补码表示法

1)补码的定义:正数的补码是它本身;负数的补码等于模与该负数绝对值之差。(对于n位二进制编码,它的模是 2 n 2^n 2n

2)补码0的表示形式:

  • [ + 0 ] 补 = [ − 0 ] 补 = 2 n + ( 士 0 ) = 100 … 0 = 00 … 0 ( m o d 2 n ) [+0]_补=[-0]_补=2^n+(士0)=100…0=00…0(mod 2^n) [+0]=[0]=2n+(0)=1000=000(mod2n)

从上述结果可知,补码0的表示是唯一的。这带来了以下两个方面的好处:一是减少了+0和-0之间的转换。二是少占用一个编码表示,使补码比原码能多表示一个最小负数。

3)求一个数的补码(在原码的基础上):

  • 对于正数,符号位取0,数值部分不变。
  • 对于负数,符号位取1,对数值部分“各位取反,末尾加1”。

4)补码表示范围(对于n位二进制编码): − ( 2 n − 1 ) -(2^{n-1}) (2n1) ( 2 n − 1 − 1 ) (2^{n-1}-1) (2n11)

二、C++正数/负数的左移和右移

在机器中,数的二进制码的表示形式是补码。

2.1 正数的左移和右移

正数的移位比较简单,左移是在二进制数的右边补0,右移是在二进制数的左边补0(因为符号位是0)。

#include <iostream> using namespace std; int main() { 
     int a = 3; // 0000 0000 0000 0000 0000 0000 0000 0011 cout << (a << 1) << endl; // 0000 0000 0000 0000 0000 0000 0000 0110:6 cout << (a >> 1) << endl; // 0000 0000 0000 0000 0000 0000 0000 0001:1 return 0; } 

2.2 负数的左移和右移

1)负数的左移:左移是在二进制数的右边补0。一个负数在左移的过程中会出现有正有负的情况,因为最高的符号位可能变成0,所以要清楚负数左移不会特殊处理符号位。如果一直左移,最终会变成0。

#include <iostream> using namespace std; int main() { 
     int a = -3; // 1111 1111 1111 1111 1111 1111 1111 1101 cout << (a << 1) << endl; // 1111 1111 1111 1111 1111 1111 1111 1010:-6 cout << (a << 30) << endl; // 0100 0000 0000 0000 0000 0000 0000 0000:2^30= cout << ((a << 30) << 2) << endl; // 0000 0000 0000 0000 0000 0000 0000 0000:0 return 0; } 

2)负数的右移:右移是在二进制数的左边补1(因为符号位是1)。如果一直右移,最终会变成-1,即二进制数变成全1,而全1在补码中就表示为-1。并且后面不管继续右移多少位,结果还是-1。

#include <iostream> using namespace std; int main() { 
     int a = -3; // 1111 1111 1111 1111 1111 1111 1111 1101 cout << (a >> 1) << endl; // 1111 1111 1111 1111 1111 1111 1111 1110:-2 cout << (a >> 2) << endl; // 1111 1111 1111 1111 1111 1111 1111 1111:-1 cout << (a >> 3) << endl; // 1111 1111 1111 1111 1111 1111 1111 1111:-1 return 0; } 

2.3 扩展(对正负数都适用,下面以正数为例)

1)移位里一个比较特殊的情况是当移位的位数等于或超过该数值类型的最大位数时,编译器会用移位的位数去模该类型的最大位数,然后按余数进行移位,如:

#include <iostream> using namespace std; int main() { 
     // 这里int类型是32位 int a = 3; cout << (a << 33) << endl; // 33 % 32 = 1,左移1位,a变成6 cout << (a >> 33) << endl; // 33 % 32 = 1,右移1位,a变成1 return 0; } 

2)另外注意,如果移位的位数没有等于或超过该数值类型的最大位数,即使移位相同的位数(通过几次移位),结果也是不一样的,如:

#include <iostream> using namespace std; int main() { 
     int a = 3; a = a << 31; cout << (a << 2) << endl; // 结果为:0 return 0; } 

这里和1)中一样总共左移了33位,但结果是0,而不是6,要注意这一点。

3)移位负数(即移位的位数是负数)

移位负数的计算是,用被移动数的数值类型的最大位数和该负数相加,再移动所得结果即可。(已测试过,不是用负数的数值类型的最大位数,而是用被移动数的)

例如:左移-31,因为a用int类型存储,而我这里int类型是32位存储,所以32+(-31)=1,即左移1位。

#include <iostream> using namespace std; int main() { 
     int a = 1; cout << (a << -31) << endl; // 32+(-31)=1,即左移1位。结果为:2 return 0; } 

注:移位负数这里我查了一些资料并测试过,但还不能肯定是这样计算,如有错,望指正。


版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/232110.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 安卓和ios之间文件互传_安卓转移到iphone12

    安卓和ios之间文件互传_安卓转移到iphone12如果之前是安卓用户,在购买iphone12新款手机之后,如何从安卓转移数据到ios?可以通过苹果官方提供的“转移到ios”应用,将安卓手机中的内容进行转移,感兴趣的朋友快来看看吧!如何将数据从安卓设备转移到iphone12可转移的内容包括:通讯录、信息历史记录、相机照片和视频、web书签、邮件帐户和日历。转移完成之后,您可以从appstore下载任何匹配的免费app。使用前准备…

    2022年9月18日
    2
  • android declare-styleable 和style,Android 关于declare-styleable属性的写法….

    android declare-styleable 和style,Android 关于declare-styleable属性的写法….我想问自定义View的时候,以下这段代码,为何要写两次一样的名称呢?我看了一些资料,说写在declare-styleable系统会自动生成数组…..我不太明白这实际应用是什么?如果说自动帮你生成了数组,方便使用,那写在外面的三个又有什么作用?能从实际应用中讲一讲吗?<?xmlversion=”1.0″encoding=”utf-8″?><resources><at…

    2022年7月13日
    15
  • JavaFX菜单ContextMenu使用

    JavaFX菜单ContextMenu使用在开发应用的过程中 想做一个类似下面截图的功能 点击菜单按钮之后 在下面显示下拉面板 该截图是华为 Hisuite 客户端 通过 ContextMenu 可以实现该功能 首先定义 GlobalMenu 继承 ContextMenu 显示这些功能选项 packagecom nii desktop widget menu importjavafx scene control ContextMe

    2025年8月28日
    1
  • navicat连接sqlserver 08001错误

    navicat连接sqlserver 08001错误1、sqlsever配置工具中将sqlserver服务启动2、sqlserver网络配置,3个都启动,然后tcpip右键属性,IP地址中将ipall的TCP动态端口删除,TCP端口填写14333、sqlserver网络配置,3个都启动,然后tcpip右键属性,IP地址中将ip2(ip地址)、ip4(127.0.0.1)的已启用选为“是”4、重启sqlserver服务5、防火墙上14…

    2022年8月30日
    4
  • 搭建spring cloud工程_阿里云开发者成长计划

    搭建spring cloud工程_阿里云开发者成长计划这里写目录标题一:环境搭建二:项目搭建一:环境搭建本次项目在Linux系统下运行,虚拟机为VMware,操作系统为Centos8,需要的工具有Docker,MySql5.7,Redis,Git。MySql5.7:安装好docker’后,pull进来MySql5.7,配置好端口映射、目录挂载等,再创建my.cnf文件来配置MySql5.7。docker下mysql配置:my.cnf【client】default-character-set=utf8【mysql】default-charac

    2022年7月28日
    12
  • [IPv6工具] 可用dns和ipv4转v6工具

    [IPv6工具] 可用dns和ipv4转v6工具

    2022年3月7日
    58

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号