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

原码、补码以及正数/负数的左移和右移文章目录一 原码和补码 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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 卷积层与池化层(bn层的原理和作用)

    构建了最简单的网络之后,是时候再加上卷积和池化了。这篇,虽然我还没开始构思,但我知道,一定是很长的文章。卷积神经网络(ConvolutionalNeuralLayer,CNN),除了全连接层以外(有时候也不含全连接层,因为出现了Globalaveragepooling),还包含了卷积层和池化层。卷积层用来提取特征,而池化层可以减少参数数量。卷积层先谈一下卷积层的工作原理。…

    2022年4月10日
    493
  • Ubuntu搭建饥荒服务器教程

    Ubuntu搭建饥荒服务器教程安装编译环境Ubuntu/Debian64-Bitsudoapt-getinstalllib32gcc1screenRedHat/CentOS32-Bityum-yinstallglibclibstdc++screenlibcurlRedHat/CentOS64-Bityum-yinstallglibc.i686libstdc++.i686screenlibcurl.i686yuminstallglibc.i686下载steamCMDwget

    2022年6月2日
    20
  • 处理线上字典插入nil值引起的崩溃

    处理线上字典插入nil值引起的崩溃

    2022年4月2日
    31
  • keil如何生成bin文件_keil4生成bin文件

    keil如何生成bin文件_keil4生成bin文件如何利用KEIL生成bin文件并且用于固件更新?生成bin文件KEIL在编译完成后在Object目录下生成axf文件,我们可以使用fromelf工具将axf文件转化为bin文件。在User选项卡中可以看到如果勾选了Run#1选项,那么在编译完成之后(AfterBuild/Rebuild),就会执行该选项下的命令。接下来详细的探讨利用fromelf.exe转换工具是如何生成bin文件的。首先我们了解fromelf.exe转换工具的语法其格式如下:fromelf[…

    2022年10月20日
    2
  • NLP词向量和句向量方法总结及实现

    NLP词向量和句向量方法总结及实现目录一、Word2Vec1、Word2Vec介绍2、Gensim实现Word2Vec3、基于Word2Vec的句向量4、基于加权Word2Vec的句向量5、基于Word2Vec的文本向量化实现二、GloVe1、GloVe介绍2、基于源码的GloVe词向量生成(Linux下实现)3、Gensim加载GloVe训练的词向量三、Doc2Vec1、Doc2V…

    2022年6月12日
    46
  • P750 内存插槽

    P750 内存插槽查看p750内存插槽占用情况lscfg-vp|grep-pDIMMMemoryDIMM:RecordName……………..VINIFlagField………………XXMSHardwareLocationCode……U78A0.001.DNWKM02-P1-C13-C2…

    2022年6月15日
    31

发表回复

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

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