看到这个标题,很多人有话要说了,切!这个东西每一本计算机基础知识的书中都有介绍的,你还拿出来Show什么嘛!我的原则是你需要就来看一看,懂就不要去理会,倒也不必讽刺两句,我相信总有需要它的人。当初我看书是没看明白的,在网上查了好多资料才有所悟。
前几天跟老婆讲原码、反码和补码的知识,老婆似懂非懂,在这里我发表一下我个人的意见,浅显的把我所理解的原码、反码和补码的知识总结一下,一来可以给不懂的人来点启示,二来也可以方便老婆以后记忆复习。理解有不对的地方希望大家予以指出,谢谢!
大家都知道数据在计算机中都是按字节来储存了,1个字节等于8位(1Byte=8bit),而计算机只能识别0和1这两个数,所以根据排列,1个字节能代表256种不同的信息,即28(0和1两种可能,8位排列),比如定义一个字节大小的无符号整数(unsigned char),那么它能表示的是0~255(0~28-1)这些数,一共是256个数,因为,前面说了,一个字节只能表示256种不同的信息。别停下,还是一个字节的无符号整数,我们来进一步剖析它,0是这些数中最小的一个,我们先假设它在计算机内部就用8位二进制表示为00000000(从理论上来说也可以表示成其他不同的二进制码,只要这256个数每个数对应的二进制码都不相同就可以了),再假设1表示为00000001,2表示为00000010,3表示为00000011,依次类推,那么最大的那个数255在8位二进制中就表示为最大的数11111111,然后,我们把这些二进制码换算成十进制看看,会发现刚好和我们假设的数是相同的,而事实上,在计算机中,无符号的整数就是按这个原理来储存的,所以告诉你一个无符号的整数的二进制码,你就可以知道这个数是多少,而且知道在计算机中,这个数本身就是以这个二进制码来储存的。比如我给你一个2个字节大小的二进制码,首先声明它表示的是无符号的整数:00000000 00000010,我们把前面的0省略,换算一下,它表示的也是数值2,和前面不同的是,它占了2个字节的内存。不同的类型占的内存空间不同,如在我的电脑中char是1个字节,int是4个字节,long是8个字节(你的可能不同,这取决于不同的计算机设置),它们的不同之处仅仅是内存大的能表示的不同的信息多些,也就是能表示的数范围更大些(unsigned int能表示的范围是0~28*4-1),至于怎么算,其实都是一样的,直接把二进制与十进制相互转换,二进制就是它在计算机中的样子,十进制就是我们所表示的数。啊哈,原来这些都是可以计算的呀,我曾经还以为不同的计算机储存的原理是不同的,取决于商家的喜好呢,呵呵。说了这么多怎么还没有提到原码、反码和补码呀,别急别急,心急吃不了热豆腐,呵呵,因为无符号的整数根本就没有原码、反码和补码。(啊,那不是被欺骗了,5555````我告诉妈妈去,哥哥欺负我)都说了别急嘛,你就不想想我说了这么半天的无符号整数,那么有符号的整数怎么办啊?
呵呵,对,只有有符号的整数才有原码、反码和补码的!其他的类型一概没有。虽然我们也可以用二进制中最小的数去对应最小的负数,最大的也相对应,但是那样不科学,下面来说说科学的方法。还是说一个字节的整数,不过这次是有符号的啦,1个字节它不管怎么样还是只能表示256个数,因为有符号所以我们就把它表示成范围:-128-127。它在计算机中是怎么储存的呢?可以这样理解,用最高位表示符号位,如果是0表示正数,如果是1表示负数,剩下的7位用来储存数的绝对值的话,能表示27个数的绝对值,再考虑正负两种情况,27*2还是256个数。首先定义0在计算机中储存为00000000,对于正数我们依然可以像无符号数那样换算,从00000001到01111111依次表示1到127。那么这些数对应的二进制码就是这些数的原码。到这里很多人就会想,那负数是不是从10000001到11111111依次表示-1到-127,那你发现没有,如果这样的话那么一共就只有255个数了,因为10000000的情况没有考虑在内。实际上,10000000在计算机中表示最小的负整数,就是这里的-128,而且实际上并不是从10000001到11111111依次表示-1到-127,而是刚好相反的,从10000001到11111111依次表示-127到-1。负整数在计算机中是以补码形式储存的,补码是怎么样表示的呢,这里还要引入另一个概念——反码,所谓反码就是把负数的原码除符号位(负数的原码除符号位和它的绝对值所对应的原码相同,简单的说就是绝对值相同的数原码相同)各个位按位取反,是1就换成0,是0就换成1,如-1的原码是0000001(注意这里只有7位,不看符号位,我这里所说的负数符号位都是1),和1的原码相同,那么-1的反码就是1111110(这也是7位,后面加上了符号位都是8位了),而补码就是在反码的基础上加1,即-1的补码是11111110+1=11111111,因此我们可以算出-1在计算机中是按11111111储存的。总结一下,计算机储存有符号的整数时,是用该整数的补码进行储存的,0的原码、补码都是0,正数的原码、补码可以特殊理解为相同,负数的补码是它的反码加1。下面再多举几个例子,来帮助大家理解!
//--- 2008年6月23日补充:
很久没有来这里了,如果不是看到有人给我私人留言被转发到我以前的老邮箱去了,我可能还不知道什么时候才发现那个“-1的反码就是11111110”的问题,看了N多批评后,觉得实在对不起各位,我已经在上面更正了,改成了7位,其实当时也是这么想的,为什么我要把符号位单独拿出来先不考虑,因为。。-128。。呵呵,自己想想为什么吧。。这个帖子好像改过几次了吧,而且当时是边想边写,如果有语言组织好的(我看到很多大学生来到了这里),归纳一下吧,只希望也和我一样,就像对一个完全不懂的人讲解,因为我深知很多想学技术通常就是被拦在了最初的门槛,其实起步了后面都不是大事,谢谢了,也算是为后来人服务吧。
//---
十进制 → 二进制 (怎么算?要是不知道看计算机基础的书去)
47 → 101111
有符号的整数 原码 反码 补码
47 00101111 00101111 00101111(正数补码和原码、反码相同,不能从字面理解)
-47 10101111 11010000 11010001(负数补码是在反码上加1)
再举个例子,学C语言的同学应该做过这道题:
把-1以无符号的类型输出,得什么结果?(程序如下)
#include
void main()
{
short int n=-1;
cout<<(unsigned short int)n<
首先在我的电脑中short int类型的储存空间是2个字节,你的可能不同,我说过,这取决于你的计算机配置。它能储存28*2=65536个不同的数据信息,如果是无符号那么它的范围是0~65535(0~216-1),如果是有符号,那么它的范围是-32768~32767(-215~215-1)。这道题目中,开始n是一个有符号的短整型变量,我们给它赋值为-1,根据我们前面所说的,它在计算机中是以补码11111111 11111111储存的,注意前面说了是2个字节。如果把它强制为无符号的短整型输出的话,那么我们就把刚才的二进制把看成无符号的整型在计算机中储存的形式,对待无符号的整型就没有什么原码、反码和补码的概念了,直接把11111111 11111111转化成十进制就是65535,其实我们一看都是一就知道它是范围中最大的一个数了。呵呵,就这么简单。你个把上面的源代码编译运行看看,如果你的电脑short int也是两个字节,那就会和我得一样的结果。你可以先用这个语句看看:cout<
补码的加减法运算
补码的加法运算规则是:
[X+Y]补= [X]补+[Y]补
该式表明,当有符号的两个数采用补码形式表示时,进行加法运算可以把符号位和数值位一起进行运算(若符号位有进位,则丢掉),结果为两数之和的补码形式。
例如用补码进行下列运算:(+33)补+(+15)补;(+33)补+(-15)补。
计算这样一个补码数时,首先要记得把相应的补码数写成二进制数(有符号位)。如图2-14所示的就是以上两个补码加法运算式。最终的结果分别是[+48]补和[+18] 补。
补码的减法运算规则是:
[X-Y]补=[X]补+[-Y]补
该式表明,求[X-Y]补可以用[X]补与[-Y]补相加来实现。
[-Y]补是对减数进行求负操作。一般称已知[Y]补求得[-Y]补的过程叫变补或求负。已知[+Y]补求[-Y]补的规则是全部位(含符号位)按位取反后再加1。
例如:已知[+15]补=00001111B,则[-15]补=11110000B+1=11110001B
或:0- [+15]补=0–10001111B=11110001B
现在例举补码减法运算示例。仍假设X=+33,Y=+15,现要求[X-Y]补。
先求得[X]补=00100001B,[Y]补=00001111B,根据以上介绍的补码负操作规则,可以得到[-Y]补=11110001B。然后再用[X]补+[-Y]补公式即可得到最终的[X–Y]补。运算过程如图2-15左图所示。如果是X= -33,Y= -15,如果仍要求[X-Y]补,则同样需要求[-Y]补,也即[-(-15)]补,实际上是要求[+15]的补码。因为已知了[-15]补=11110001B,根据前面介绍的补码负操作规则,可以很快得出[+15]补=00001111B。这样[X-Y]补就等于[-33]补+[+15]补,运算过程如图2-15右图所示。
图2-15 两个补码减法运算示例 |