首先明白一点:
char a=0;(这里char的取值范围是-128~127)
char b=~a;(按位取反,必须明白是如何取的)
printf("%d",b);
结果:
b内存表示 ,即11111111
也就是说对a按位取反是对a的补码按位取反,取反后的是b的补码,即b在内存中的存储方式,我们需要做的就是要把b从补码转换成原码,即b在屏幕上的显示。
正数,原码跟补码一样
负数,值,原码,符号位不变其它取反,+1
1000 0000,那么,它的原码是什么呢?
从补码求原码的方法跟原码求补码是一样的
先保留符号位其它求反: 1111 1111, 再加1:11000 0000, 超过了8位了
对,用8位数的原码在这里已经无法表示了
关键就在这里,补码1000 0000 为 -128 是不用怀疑的(上面的穷举),
那么,回到原码处, 它的原码也是 1000 0000(超出的自动丢失),
1000 0000 在原码表示什么呢? -0, 但补码却规定0没有正负之分
转换一下思路,看看计算机里,是怎么运算的:
对于负数,先取绝对值,然后求反,加一
-128 -> 128-> 1000 0000 -> 0111 1111-> 1000 0000
现在明确了吧
所以, 8位有符号的整数取值范围的补码表示
1000 0000 到 0000 0000, 再到 0111 1111
即-128 到 0, 再到 127
最终-128 ~ +127
第一次修订 2009-5-6 14:11
---------------------
1.模的概念(我只讲个例子,具体的可以查数学中的"同余模")
在日常生活中,有许多化减为加的例子。例如,时钟是逢12进位,12点也可看作0点。
当将时针从10点调整到5点时有以下两种方法:
1.将时针逆时针方向拨5格,相当于做减法: 10-5=5
2.将时针顺时针方向拨7格,相当于做加法:10+(12-5)=12+5=5(模为 12)
2.模的运用(采用模得到补码)
1.补码的得来:是为了让负数变成能够加的正数,so,负数的补码=模-负数的绝对值
比如:-1 补码:1111 1111(10000 0000 -1得来)
当一个数要减1的时候,可以直接加1111 1111
2.原码的得来:(负数的原码,直接把对应正数的最高位改为1)
原码能够直观的表示一个负数(能直观的把真值显示出来,如 -1为1000 0001
其中最高位表示符号位,不进行算术计算)
3.总结:补码相加,到第9位才舍弃(模10000 0000)
原码相加,到第8位舍弃(模1000 0000)
反码相加,到第8位舍弃(模1000 0000)
3.原码和补码之间转换:
1.补码=原码减1,再取反(便于理解)
或补码= 反码+1(便于描述和推理)
2.演示:补码=原码减1,再取反
如-1的原码1000 0001-->1000 0000(减1后)-->1111 1111(取反后)补码
3.演示:补码= 反码+1)
如-1的原码 1000 0001-->11111110(反码)-->1111 1111(加1)补码
4.重点:(特别是在有进位的时候)
原码和反码的最高位是符号位,不参加算术运算,模为1000 0000(比补码少一个0)
而补码所有位都可以相加,模为10000 0000(最高位不是符号位,补码是通过模 减去 负数绝对值得到的)
5.推断-128的原码和补码(用补码= 反码+1)
1.关于原码1000 0000,表示的是-0,还是-128呢?(答案是-128而不是-0)
1.先看看原码的概念吧:正数的符号位为0,负数的符号位为1,其它位按照一般的方法来表示数的绝对值
2.0是负数吗?0既不是正数也不是负数,那么它的符号位到底是0还是1呢?(0的符号位为0,不能为1)
3.看看负数补码的公式:负数的补码=10000 0000(模)-数的绝对值
比如:-1 1111 1111 =10000 0000-0000 0001
-2 1111 1110 =10000 0000-0000 0010
现在假设-0为负数,那么
-0的补码应该是10000 0000 - 0(这个0,姑且教0的绝对值吧)=0000 0000
反码:1111 1111(0000 0000 -1=0000 0000 +1111 1111=11111111)
原码:1000 0000
现在来推-128
-128的补码:10000 0000 - 1000 0000(+128没有符号位)=1000 0000
反码:1111 1111(1000 0000 -1=1000 0000+1111 1111=11111111)(补码-1)
原码:1000 0000(反码取反)
从上面看来,一个原码对应了2个补码
但是仔细分析:原码的概念,负数的符号位为1,但是0不是负数,所以不能用此公式
0也不是正数,但是可以把0定义为原码、反码和补码都一样(即0000 0000)
而且据说可以推断出0的补码只有一个(有兴趣的可以去推一下,呵呵)
现在原码1000 0000就唯一表示-128了,而不会表示出-0,因为-0不能用这个公式计算
现在,补码1000 0000的原码是1000 0000(已证明),那么原码1000 0000的补码是1000 0000吗?
原码 1000 0000 (-128,进位被舍去)
反码 1111 1111
补码 1000 0000(1111 1111(反码) + 1=1000 0000,这里实际上真正相加的是1111 1111后面的7位,
第1位是符号位始终不会变,所以,当进到第8位的时候,就表示溢出了,会被舍弃)
2.综上所述:1.-128的补码和原码一样都是1000 0000,
2.0的原码、反码和补码都一样(即0000 0000)
3.如果把-0当做负数,1000 0000就会有歧义(事实上0的补码只有一个0000 0000)
第一次的手稿2009-5-5 22:47
-----------------
1.使用反码的意义:
1.使符号位能与有效值部分一起参加运算,从而简化运算规则。从而可以简化运算器的结构,提高运算速度;
(减法运算可以用加法运算表示出来。)
2.加法运算比减法运算更易于实现。使减法运算转换为加法运算,进一步简化计算机中运算器的线路设计。
2.负数的二进制数串表示一般用补码:(如何通过原码推补码,特别是-128的解释)
1.先给出3个原则:
1.因为使用补码可以将符号位和其他位统一处理,同时,减法也可以按加法来处理,即如果是补码表示的数,
不管是加减法都直接用加法运算即可实现。
2.两个用补码表示的数相加时,如果最高位(符号位)有进位,则进位被舍弃(模的概念,补码的模10000 0000)
比如:1111 1111(-1) +1000 0001(-127)=10000000(-128,实际上最高位有3个1,进位一次后,还保留一个1)
1111 1110(-2) + 0000 0100(4) = 0000 0010(2)
3.模的规则:(自己的推断)
1.补码的模为10000 0000
2.反码的模为1000 0000(从反码的定义也能够知道,即反码的运算不涉及符号位)
3.模的解释
在日常生活中,有许多化减为加的例子。例如,时钟是逢12进位,12点也可看作0点。
当将时针从10点调整到5点时有以下两种方法:
1.时针逆时针方向拨5格,相当于做减法: 10-5=5
2.时针顺时针方向拨7格,相当于做加法:10+(12-5)=12+5=5(模为 12)
2.原码、反码和补码的定义:(主要讨论负数的)
1.正整数的原码、反码和补码都一样
2.负数:
1.原码就是原来的表示方法
2.反码是 原码除符号位(最高位)外取反
3.补码=反码+1
3.举例:以一个单字节来说:(即8位)
-1 原码 1000 0001(通过原码得到真值)
反码 1111 1110
补码 1111 1111(通过补码得到二进制)
-2 原码 1000 0010
反码 1111 1101
补码 1111 1110
**如此类推:原码 1000 0000(-128)(重点)
反码 1111 1111
补码 1000 0000(1111 1111 + 1=1000 0000,这里实际上真正相加的是1111 1111后面的7位,
第1位是符号位始终不会变,所以,当进到第8位的时候,就表示溢出了,所以会被舍弃,
也就是说反码的模是1000 0000,而补码的模是:10000 0000比反码多一位)
如果用补码反推原码
补码1000 0000
反码1111 1111(1000 0000 -1=1000 0000+11111111(相当于2个补码相加,可用模的规则)=1111 1111)
原码1000 0000
4.感慨:很多群人解释不通了,就武断的说-128的二进制为1000 0000,并断定它没有反码和原码,还说是"规定"
而我怎么也没有找到官方的这么个规定(个人觉得这是不严谨的也是不负责任的,呵呵)
5.具体的计算演示:
1+(-1)=0
0000 0001 + 1111 1111=0000 0000
1+(-2)=-1
0000 0001 + 1111 1110=1111 1111(-1)
2+(-1)=1
0000 0010 + 1111 1111=0000 0001
(-128)+1=-127
1000 0000 +0000 0001=1000 0001(补)
1000 0001(补码)
1000 0000(反码=补码-1)
1111 1111(原码=-127)
3.有一个不正确的解释,貌似还写成书了(个人认为)
采用补码表示还有另外一个原因,那就是为了防止0的机器数有两个编码。原码和反码表示的0
有两种形式+0和-0,而我们知道,+0和-0是相同的。这样,8位的原码和反码表示的整数的范围就是-127~+127
(11111111-01111111),而采用补码表示的时候,00000000是+0,即0;10000000不再是-0,而是-128,这样,
补码表示的数的范围就是-128~+127了,不但增加了一个数得表示范围,而且还保证了0编码的唯一性。
我的观点:包括写上面的话的人自己也说过,10000000(补码)没有反码和原码,既然这样,如何得出结论
10000000曾经表示的是-0,其实通过上面的分析,1000 0000是有反码(1111 1111)和原码的(1000 0000)
4.一些好的概念:
由于计算机中符号和数字一样,都必须用二进制数串来表示,因此,正负号也必须用0、1来表示。
用最高位0表示正、1表示负, 这种正负号数字化的机内表示形式就称为“机器数”,
而相应的机器外部用正负号表示的数称为“真值”,将一个真值表示成二进制字串的机器数的过程就称为编码