细说原码,补码,反码和移码【附示例】

细说原码,补码,反码和移码【附示例】

【引言】

在我们人类的日常生活的中,数字是一种表示数的书写符号,它可以被用于表示,传递,记录或者是运算。在日常生活中,大部分人类交流都是使用的十进制。十进制是以10为基础的数字系统,是世界上应用最为广泛的进制位,人类无时不刻都要使用它。

十进制有无位值和具有位置的概念两大类:

无位值概念的十进制:古希腊、古埃及和古印度的佉卢十进制和婆罗米十进制都属于这一类。

具有位置概念的十进制,特称为十进位制,如中国古代的算筹数和印度阿拉伯数字。

人类算数采用十进制,可能也跟人类有十根手指有关。而在我们日常也存在这么一部分人,他们很少与他人交流,更多得时间与机器进行交流,他们间接的使用”二进制“与机器交流,这种人就是程序媛/猿。

那么什么是二进制呢?就是在数学上或者数字电路中以2为基数的基数的一套记数系统,它包括0和1这两个数。那么什么叫做基数呢?经查资料后我们得知:一种进位制中可以使用的数字符号的数目称为这种进位制的基数或底数。若一个进位制的基数为n,即可称之为n进位制,简称n进制。现在最常用的进位制是十进制,这种进位制通常使用10个阿拉伯数字(即0-9)进行记数。

那么我们的程序猿哥哥,程序媛姐姐为什么要使用“二进制”与机器交流呢,而不去使用我们日常生活中的十进制呢?

简单的来说是因为:计算机不懂得10进制。

稍微复杂的来说是因为:在我们经典计算机的内部是由很多的集成电路组成的,其中集成电路中的元件受于涉及限制只能发送和接受高电压和低电压这两种状态,而我们的线路也只能传递这两种状态。如果大家接触过单片机就能明白,比如存在这么一个单片机:

ESP8266_GPIO.jpg

我们写好程序后烧录进此单片机,假设我们的程序是每隔一秒向数字阵脚5(GPIO 5 )输出一个高电平然后输出低电平,那么我们则需要将所需要输出的数字阵脚5与GND接地线连接起来分别连接到所需要连接的外部元器件对应的正负极可根据内置时钟定时向数字阵脚5输出信号从而驱动与其元器件的通信,从而实现想实现的功能(若所需电压不够则彼此可连接vcc电压以提供工作电压)。

通过这个例子我们深刻的认识到了二进制对于计算机的重要性不言而喻。

如果你像我一样还是觉得这依然不够硬核,但又不想掉更多的头发。那么你可以尝试一下反推使用其他进制。

当我们反推一下不使用二进制时,而转而使用其他进制位作为计算机的后果则很恐怖,举个例子:

假设我们使用10进制,那么每一种开关将包含10可能种状态(这甚至比薛定谔的猫还恐怖)。考虑对于目前的计算机硬件和软件来说是非常不现实的,或许将来量子计算机可能能实现。但据我所知,量子计算机也仅能实现同时存在0和1这两种相干的叠加态,实现2^N方,算力惊人。(叠加态简单的来说就是你向你心仪的女神求婚时,会同时存在同意和拒绝这两种状态,量子力学的深奥,非我能弄清楚,但是我总能感觉女生的心思似乎和量子力学中的叠加态一样复杂。)

总之,科学在不断的发展,我们也要不断的学习。(譬如我刚刚查阅资料得知,三进制使用的效率比二进制的还高。有为未知、是、否这三种状态,对于编程而言我觉得这是好事,至少不用单独弄出来定义个未知型了,我觉得可以改造一下布尔型,再给布尔型添加一种未知的状态。但是二进制计算机通用必定有它的原因,部分原因由此文中的引言所述。)

当我们清楚的得知了使用二进制对于计算机的的重要性后以及为什么要使用二进制时,接下来我们不妨思考一下,既然我们十进制中有基本的四则运算法,比如:1+9=10,10-9=1=等。那么二进制是不是也有呢?答案是二进制也有的而且n进制也有呢!

咳咳,由于二进制的运算是计算机的重点,我们此处就不讲其他进制的运算了,如果又兴趣可以自行尝试。二进制的运算是计算机的所有程序运算的根本,故一定要好好掌握。

移码

在学习二进制运算之前,我觉得我们有必要好好学习一下,位移这个概念。

简单的来说,位移运算就是指将二进制位的全部元素的进行左/右移动的操作。

比如将(1001)2左移一个字节我们就得到了(10010)2。

当我们尝试将(1001)2和(10010)2分别转成十进制时:

(1001)2  = 1 x 2^0 + 0 x 2^1 + 0 x 2^2 + 1 x 2^3
           = 1 + 8 = 9
(10010)2 = 0 x 2^0 + 1 x 2^1 + 0 x 2^2 + 0 x 2^3 + 1 x 2^4
           = 2 + 16 = 18

依次推下去,我们会惊奇的发现(10010)2刚好是(1001)2的2倍。

比如将(1001)2左移两个字节我们就得到了(100100)2.

当我们尝试将(1001)2和(100100)2分别转成十进制时:

(1001)2   = 9
(100100)2 = 0 x 2^0 + 0 x 2^1 + 1 x 2^2 + 0 x 2^3 + 0 x 2^4 + 1 x 2^5
            = 4 + 32 = 36

依次推下去,我们会惊奇的发现(100100)2刚好时(1001)2的4倍。

左移1位:2倍,左移2位:4倍。经过尝试继续往下面推,同理可得出: 2^x = n(x为向左移位数,n为多少倍),当我们右移操作则是缩小:  2^(1/x) = n  倍。

你可能会感到疑惑的地方!当你尝试将某个奇数缩小1/x倍时,例如:将3缩小1/2倍时所得到得结果会产生小数1.5。那么这个怎么用二进制表示呢?在此之前我们得先讲见什么是原码。

【原码】

刚才我们没有详细的介绍右位移的操作,只是点明了右移会导致的结果。因为当我们进行右移操作后,空出来的高数数值会有0和1这两种数值,而这两种高位数值又分别代表的二进制的负数和正数。莫慌,只要我们弄清楚什么时候补0什么时候补1就行了。

下面我们就来掌握一下二进制中的正数和负数的表示方法:就一句话,符号位为0的二进制数表示正数,符号位为1的二进制数表示负数。那么什么叫做符号位呢?符号位就是二进制的最高位。你说它为什么要放最高位呢,不直接像十进制那样给它在前面按一个负号呢?因为使用符号位方便实现,而且使用符号位的主要原因是计算机世界里面没有减法,计算机在做减法的时候就是在做加法,在使用负数时就使用补数这个东西。

假设用8位表示一个数,则+11和-11分别表示为(00001011)2和(10001011)2。

当我们在十进制的环境下计算11-11时结果等于0,但使用二进制的原码直接进行计算时,因为计算机没有减法,这个时候直接相减就会出现错误,譬如:(00001011)2 + (10001011)2 = (1001100)2,经过检验发现是不符合的,说明我们不能使用原码直接进行减运算。 

另外顺带提一下:

假设我们采用8位为一组2进制,第一位是符号位。因为第一位是符号位,故这8位二进制的取值范围就是:

[(11111110)2 , (01111111)2]

转成十进制用区间表示法即:

[-127,127]

【反码】

正数的反码与原码相同,负数的反码符号位为1,其余各位为该数绝对值的原码按位取反。例如,-11的反码为:(11110100)2。

同样对于11 +(-11)的加法,使用反码的结果是:

(00001011)2 +(11110100)2 =  (11111111)2

将(11111111)2转换成原码后得(10000000)2得知结果为负0,而在我们得普遍观念中,0是不分正负的,但为了考虑其符号位,所以我们将其归为正数。反码的符号位可以直接参与计算,有了反码后减法也可以转换为加法进行计算,至此我们已经解决了计算机的加减法,但未彻底解决,所以接下来我们要学习一下补码这一概念。

【补码】

正数的补码与原码相同。负数的补码是概述的反码加上1,这个加1就是“补”。例如,-11的补码为(11110101)2。

对于11 +(-11)这样的加法,利用补码我们可以完美的解决,而不会得得出像使用反码得出的负0这样的结果,譬如:

(00001011)2 + (11110101)2  = (00000000)2

最后我们得出了0这个正确的数,这说明我们使用补码的计算的结果是正确的。

另外值得注意的是:对于一个用补码表示的数,要计算其原码,只要对它再次求反加求补即可。

下面我们来看两个例子:

【运算示例】

11 - 11 = 0
11 - 12 = -1

减法.png


回复列表



回复操作

正在加载验证码......

请先拖动验证码到相应位置

发布时间:2020-02-06 23:25:20

修改时间:2020-03-01 20:41:46

查看次数:90

评论次数:0