痞子衡嵌入式:不可不知的计算机原理知识(1)- 整数表示(原码/反码/补码)


  大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家讲的是计算机原理知识点-整数表示

  本系列痞子衡会给大家介绍一些关于计算机原理的有趣的知识点,今天是系列第一节课,痞子衡要讲的是计算机中最基础的知识,即整数数据表示法。

  现实生活中的所有信息在计算机看来就是一堆数据,计算机的工作就是和数据打交道。简单来说,计算机最核心的功能就是两个:存储数据、处理数据。计算机首先得要能正确地存储用户数据,有了数据之后,计算机还要能够按照用户要求处理(运算)数据。今天痞子衡要讲的就是数据(整数)在计算机中是怎么存储(表示)的。

一、何谓进制

  学过数字电路的朋友肯定知道数据的进制表示法,常见的有二进制、八进制、十进制、十六进制表示法。在现实生活中我们所用的数据表示法是十进制,即由0-9共10个数字表示所有数值。

  任意进制转换成十进制的公式为Xn-1X...X1X0=Xn-1*Rn-1+...X1*R+X0,其中R为当前被转换进制的权重值,二进制则R=2,八进制R=8,十进制R=10,十六进制R=16。X可取值当前被转换进制所有的单个数字(值)。

  计算机就是大规模集成数字电路,数字电路只有两种电平状态(低/高),对应到数字表示就是0,1,所以实际上计算机只认二进制,所有保存在计算机中的数据都是由二进制来表示的。

二、整数编码

2.1 正负数表示(原码)

  数据在计算机中都是用二进制来表示的。对于无符号整数(正整数),比如uint8_t型,8个bit均为数据位,用二进制表示其范围为8'b00000000 ~ 8'b11111111(0~255),这种所有bit均为数据位以表示无符号整数的编码方式即为原码

  但很多时候我们不仅要保存正整数,还要保存负整数,此时便涉及到有符号整数的表示方法了,此时编码规定最高bit表示符号(0为正,1为负),其余bit表示数据位,这种表示有符号整数的编码方式实际上也是原码。对于int8_t型,bit7为符号位,bit6-0为数据位,用二进制表示其范围为8'b10000000 ~ 8'b01111111(-128~127),有朋友可能会对这里有疑问,似乎按照编码规定能表示的整数范围应该是-127 ~ 127,但实际并不是如此,具体痞子衡在下面会解释。

2.2 减法的实现(反码)

  数字电路里我们都听说过加法器,但没有减法器的说法,说明计算机实际上仅支持加法运算,对于正整数做加法运算用原码没有任何疑义。那么对于无符号整数做减法运算(等同于有符号数的加法运算)怎么实现?我们尝试着用原码来代入运算,比如129-7(即129+(-7)):

   8'b10000001(129原码)
 + 8'b10000111(-7原码)
--------------
 = 8'b????????(符号位如何参与运算?)
 =9'b100001000(不区别符号位,直接运算,最高bit由于溢出被自动丢弃)
 = 8'b00001000(结果为8)

  我们似乎遇到了困难,有符号运算数的符号位如何参与运算?如果我们不区别对待符号位,直接把它当做数据位进行计算,得出的结果显然是不对的,所以原码是无法被用作减法/有符号数的计算的。为了解决这个问题,此时引入了第二种编码方式规定(反码),即正数的反码与原码相同,负数的反码等于原码除了符号位外,其余数据位全部取反。有了反码,此时我们用反码重新计算129-7:

   8'b10000001(129反码)
 + 8'b11111000(-7反码)
--------------
 =9'b101111001(最高bit由于溢出被自动丢弃)
 = 8'b01111001(结果为反码,由于最高bit为0,即表示正数,所以等同于原码,其值为122)

2.3 消除+/-0之争(补码)

  反码看起来似乎解决了减法问题,不妨让我们再做一个减法运算,比如5-5,我们尝试再一次用反码解决问题:

   8'b00000101(5反码)
 + 8'b11111010(-5反码)
--------------
 = 8'b11111111(结果为反码)
 = 8'b10000000(转换成原码,根据有符号数原码编码规定解析为-0)

  -0是等于0的,运算的结果是对的,但是不是总感觉哪里不对?是的,原码8'b00000000表示+0,我们已经有+0来表示0了,再用-0表示0显得多此一举,浪费了一个编码值。怎么解决这个问题?此时引入第三种编码方式规定(补码),正数的补码与原码相同,负数的补码等于反码加1.那现在我们尝试用补码来重新计算5-5:

   8'b00000101(5补码)
 + 8'b11111011(-5补码)
--------------
 =9'b100000000(最高bit由于溢出被自动丢弃)
 = 8'b00000000(结果为补码,由于最高bit为0,即表示正数,所以等同于反码,也等同于原码,其值为+0)

  上述运算中使用补码消除了运算结果为-0的问题,但还是没有告诉我们8'b10000000的值到底是多少?显然不应该是-0,那么应该要怎么解析8'b10000000?有朋友说答案是-128,是的,前面我们已经在原码一节中给出了答案,那如何来理解这个答案?首先我们得要从标准原码定义的角度来说-128,按照定义-128的原码应该是9'b110000000,转换成补码还是9'b110000000,原码与补码一致,截断最高位后可得8'b10000000,讲到这里,我们似乎有点明白-128的由来了,但这样真的靠谱吗?代入运算会不会影响运算结果的正确性?我们来试试看-128+17:

   8'b10000000(-128补码)
 + 8'b00010001(17补码)
--------------
 = 8'b10010001(结果为补码)
 = 8'b10010000(转换为反码)
 = 8'b11101111(转换为原码,由于最高bit为1,即表示负数,其值为-111)

  由于用8'b10000000来表示-128参与运算并不会导致结果错误,那么何不直接约定用8'b10000000来表示-128呢?好,就这么愉快的决定了!这就是-128=8'b10000000的由来。其实就是计算机里的一个异常的人为规定而已!

2.4 编码小结

  无论uint8_t/int8_t型数据全部使用补码的方式在计算机中进行存储,其中int8_t型数据范围内-128是个异常规定,无法用补码编码规则直接解释,但计算机可以自动理解识别。
  为了巩固知识,我们做个小练习:

// a,b,c,d,e,f分别等于多少?
uint8_t a = -1;
uint8_t b = -128;
uint8_t c = -129;
int8_t d = 128;
int8_t e = 129;
int8_t f = -129;
// 答案: a = 255, b = 128, c = 127, d = -128, e = -127, f = 127

  至此,计算机原理知识点之整数表示痞子衡便介绍完毕了,掌声在哪里~~~

欢迎订阅

文章会同时发布到我的 博客园主页CSDN主页知乎主页微信公众号 平台上。

微信搜索"痞子衡嵌入式"或者扫描下面二维码,就可以在手机上第一时间看了哦。

posted @ 2017-03-26 21:55  痞子衡  阅读(1521)  评论(0编辑  收藏  举报