首先说一句在8位2进制中超粗范围时候符号位不仅是符号位还是数值位,其实这时候数据是10000000
就是-128 就是所谓的-0,但是这里表示的-128 因为-0 +0补码表示是一样的所以使用00000000就是正零来表示零,这时候-128没有原码与反码,只有补码就是在计算机中保存的形式 10000000

-128,绝对值128,有符号数值范围是-127到+127,所以128的二进位是要用2字节内存保存,即16位,所以128的二进制码是(中括号只是表示一个字节)
[00000000][10000000]
以上是+128的原码,同时也是+128的补码
-128就是要+128的原码全部取反再加1:
+128的原码:[00000000][10000000]
取反就得到:[11111111][01111111]
再加1得到了:[11111111][10000000],这就是128的补码

*补码是数据在内存的储存形式
要求-128的原码,只需把+128的原码的最高位(符号位)更改就可:
+128的原码:[00000000][10000000]
-128的原码:[10000000][10000000]

*由原码求补码:除符号位外,其它全取反再加1
*所以,求负数的二进制补码至少有上述两种:
 1.取绝对值,求绝对值二进码,全部取反再加一
 2.取绝对值,求绝对值二进码,最高位改为1,除符号位外其它取反再加1

当然,如果保存-128的变量是4字节的,按上面方法可得到
-128原码[10000000][00000000][0000000][10000000]
-128补码[11111111][11111111][1111111][10000000]
------------------------
补充:
8位二制码[10000000]的10进制值,如果储存它的变量是无符号类型,则取值是128
但如果按有符号来读取,则是-126
计算如下:[由补码求原码值]
补码:[10000000]
除符号位全取反得[11111111]
减1得到原码[11111110],这是-126的原码

所以,如果变量是 有符号short (短整型类,C语言中有),这个类型的变量取值范围是 -127到+127
则127+1不会等于128,而是-126:
[0111111]+[0000001]=[1000000](-126的补码)
但是,如果它是无符号short integer,则它的范围是0到255,127+1=128:
[0111111]+[0000001]=[1000000](正数128的8位2进制补码)
同理,  [1111111]按无符号short 读取是255,按有符号short   则是 -1
      
     数值在计算机中表示形式为机器数,计算机只能识别0和1,使用的是二进制,而在日常生活中人们使用的是十进制,"正如亚里士多德早就指出的那样,今天十进制的广泛采用,只不过我们绝大多数人生来具有10个手指头这个解剖学事实的结果.尽管在历史上手指计数(5,10进制)的实践要比二或三进制计数出现的晚."
                                                                                                                                                                                               (摘自<<数学发展史>>有空大家可以看看哦~,很有意思的).为了能方便的与二进制转换,就使用了十六进制(2 4)和八进制(23).下面进入正题.
       数值有正负之分,计算机就用一个数的最高位存放符号(0为正,1为负).这就是机器数的原码了.假设机器能处理的位数为8.即字长为1Byte,原码能表示数值的范围为
(-127~-0 +0~127)共256个.
       有了数值的表示方法就可以对数进行算术运算.但是很快就发现用带符号位的原码进行乘除运算时结果正确,而在加减运算的时候就出现了问题:
( 1 ) 10- ( 1 )10 = ( 1 )10 + ( -1 )10 = ( 0 )10
(00000001)原 + (10000001)原 = (10000010)原 = ( -2 ) 显然不正确.
    因为在两个正整数的加法运算中是没有问题的,于是就发现问题出现在带符号位的负整数身上,于是引出了反码(对于正整数原码、反码是一样的,而负整数的反码是原码除最高位(符号位)外其余所有位的逐位求反。).反码的取值空间和原码相同且一一对应. 下面是反码的减法运算:
( 1 )10 - ( 1 ) 10= ( 1 ) 10+ ( -1 ) 10= ( 0 )10
(00000001) 反+ (11111110)反 = (11111111)反 = ( -127) 反= ( -0) 还有问题?!
( 1 )10 - ( 2)10 = ( 1 )10 + ( -2 )10 = ( -1 )10
(00000001) 反+ (11111101)反 = (11111110)反 = ( -126) 反 =( -1 ) 正确
问题出现在(+0)和(-0)上,在人们的计算概念中零是没有正负之分的.(印度人首先将零作为标记并放入运算之中,包含有零号的印度数学和十进制计数对人类文明的贡献极大).
于是又引入了补码(用最高位表示符号位,如果是0表示正数,如果是1表示负数,剩下的7位用来存数的绝对值的话,能表示128个数的绝对值,再考虑正负两种情况,128*2还是256个数。首先定义0在计算机中储存为00000000,对于正数我们依然可以像无符号数那样换算,从00000001到01111111依次表示1到127。那么这些数对应的二进制码就是这些数的原码(和原码一样)。到这里很多人就会想,那负数是不是从10000001到11111111依次表示-1到-127,那你发现没有,如果这样的话那么一共就只有255个数了,因为10000000的情况没有考虑在内。所以-1到-127不能那样表示(和原码的表示方法相同了,当然错了)。实际上,10000000在计算机中表示最小的负整数,即-128(原指-0的)。因为 -128+1=-127,那么把10000000加上1即10000001表示-127就容易计算很多了。这样,从10000001到11111111就刚好依次表示-127到-1。这就是所谓的补码。). 那么补码是怎样直接地转换得来呢?负数的补码就是对反码加一;而正数不变,正数的原码反码补码是一样的.在补码中用(-128)代替了(-0),所以补码的表示范围为:
(-128~0~127)共256个.
注意:当字长为8位时,(-128)没有相对应的原码和反码, (-128) = (10000000) (为什么?还有为什么8位整数表示的范围是-128~127,而不是-127~128呢?想过没有,为什么二进制10000000在原码和反码中表示0,在补码中它不表示0,保证了0表示的唯一性,但是它为什么表示负数,而不是正数,你也许会说,因为它符号位是1呀,表示负数呀,对,继续,+128我们用补码怎么表示,包括符号位,表示为010000000,超过了2个字节,如果截取低8位,那么是10000000,最高位(符号位)是1,表示的是一个负数了!我们再看看-128的机器码是多少,原码110000000,反码101111111,补码110000000,截取低8位即10000000,表示的是一个负数。)

补码的加减运算如下:
( 1 ) 10- ( 1 ) 10= ( 1 )10 + ( -1 )10 = ( 0 )10
(00000001)补 + (11111111)补 = (00000000)补 = ( 0 ) 正确
( 1 ) 10- ( 2) 10= ( 1 )10 + ( -2 )10 = ( -1 )10
(00000001) 补+ (11111110) 补= (11111111)补 = ( -1 ) 正确
所以补码的设计目的是:
⑴使符号位能与有效值部分一起参加运算,从而简化运算规则.
⑵使减法运算转换为加法运算,进一步简化计算机中运算器的线路设计
所有这些转换都是在计算机的最底层进行的,而在我们使用的汇编、C等其他高级语言中使用的都是原码。看了上面这些大家应该对原码、反码、补码有了新的认识了吧!


-128,绝对值128,有符号数值范围是-127到+127,所以128的二进位是要用2字节内存保存,即16位,所以128的二进制码是(中括号只是表示一个字节)
[00000000][10000000]
以上是+128的原码,同时也是+128的补码
-128就是要+128的原码全部取反再加1:
+128的原码:[00000000][10000000]
取反就得到:[11111111][01111111]
再加1得到了:[11111111][10000000],这就是128的补码

*补码是数据在内存的储存形式
要求-128的原码,只需把+128的原码的最高位(符号位)更改就可:
+128的原码:[00000000][10000000]
-128的原码:[10000000][10000000]

*由原码求补码:除符号位外,其它全取反再加1
*所以,求负数的二进制补码至少有上述两种:
 1.取绝对值,求绝对值二进码,全部取反再加一
 2.取绝对值,求绝对值二进码,最高位改为1,除符号位外其它取反再加1

当然,如果保存-128的变量是4字节的,按上面方法可得到
-128原码[10000000][00000000][0000000][10000000]
-128补码[11111111][11111111][1111111][10000000]
------------------------
补充:
8位二制码[10000000]的10进制值,如果储存它的变量是无符号类型,则取值是128
但如果按有符号来读取,则是-126
计算如下:[由补码求原码值]
补码:[10000000]
除符号位全取反得[11111111]
减1得到原码[11111110],这是-126的原码

所以,如果变量是 有符号short (短整型类,C语言中有),这个类型的变量取值范围是 -127到+127
则127+1不会等于128,而是-126:
[0111111]+[0000001]=[1000000](-126的补码)
但是,如果它是无符号short integer,则它的范围是0到255,127+1=128:
[0111111]+[0000001]=[1000000](正数128的8位2进制补码)
同理,[1111111]按无符号short 读取是255,按有符号short   则是 -1

   数值在计算机中表示形式为机器数,计算机只能识别0和1,使用的是二进制,而在日常生活中人们使用的是十进制,"正如亚里士多德早就指出的那样,今天十进制的广泛采用,只不过我们绝大多数人生来具有10个手指头这个解剖学事实的结果.尽管在历史上手指计数(5,10进制)的实践要比二或三进制计数出现的晚."
                                                                                                                                                                                               (摘自<<数学发展史>>有空大家可以看看哦~,很有意思的).为了能方便的与二进制转换,就使用了十六进制(2 4)和八进制(23).下面进入正题.
       数值有正负之分,计算机就用一个数的最高位存放符号(0为正,1为负).这就是机器数的原码了.假设机器能处理的位数为8.即字长为1Byte,原码能表示数值的范围为
(-127~-0 +0~127)共256个.
       有了数值的表示方法就可以对数进行算术运算.但是很快就发现用带符号位的原码进行乘除运算时结果正确,而在加减运算的时候就出现了问题:
( 1 ) 10- ( 1 )10 = ( 1 )10 + ( -1 )10 = ( 0 )10
(00000001)原 + (10000001)原 = (10000010)原 = ( -2 ) 显然不正确.
    因为在两个正整数的加法运算中是没有问题的,于是就发现问题出现在带符号位的负整数身上,于是引出了反码(对于正整数原码、反码是一样的,而负整数的反码是原码除最高位(符号位)外其余所有位的逐位求反。).反码的取值空间和原码相同且一一对应. 下面是反码的减法运算:
( 1 )10 - ( 1 ) 10= ( 1 ) 10+ ( -1 ) 10= ( 0 )10
(00000001) 反+ (11111110)反 = (11111111)反 = ( -127) 反= ( -0) 还有问题?!
( 1 )10 - ( 2)10 = ( 1 )10 + ( -2 )10 = ( -1 )10
(00000001) 反+ (11111101)反 = (11111110)反 = ( -126) 反 =( -1 ) 正确
问题出现在(+0)和(-0)上,在人们的计算概念中零是没有正负之分的.(印度人首先将零作为标记并放入运算之中,包含有零号的印度数学和十进制计数对人类文明的贡献极大).
于是又引入了补码(用最高位表示符号位,如果是0表示正数,如果是1表示负数,剩下的7位用来存数的绝对值的话,能表示128个数的绝对值,再考虑正负两种情况,128*2还是256个数。首先定义0在计算机中储存为00000000,对于正数我们依然可以像无符号数那样换算,从00000001到01111111依次表示1到127。那么这些数对应的二进制码就是这些数的原码(和原码一样)。到这里很多人就会想,那负数是不是从10000001到11111111依次表示-1到-127,那你发现没有,如果这样的话那么一共就只有255个数了,因为10000000的情况没有考虑在内。所以-1到-127不能那样表示(和原码的表示方法相同了,当然错了)。实际上,10000000在计算机中表示最小的负整数,即-128(原指-0的)。因为 -128+1=-127,那么把10000000加上1即10000001表示-127就容易计算很多了。这样,从10000001到11111111就刚好依次表示-127到-1。这就是所谓的补码。). 那么补码是怎样直接地转换得来呢?负数的补码就是对反码加一;而正数不变,正数的原码反码补码是一样的.在补码中用(-128)代替了(-0),所以补码的表示范围为:
(-128~0~127)共256个.
注意:当字长为8位时,(-128)没有相对应的原码和反码, (-128) = (10000000) (为什么?还有为什么8位整数表示的范围是-128~127,而不是-127~128呢?想过没有,为什么二进制10000000在原码和反码中表示0,在补码中它不表示0,保证了0表示的唯一性,但是它为什么表示负数,而不是正数,你也许会说,因为它符号位是1呀,表示负数呀,对,继续,+128我们用补码怎么表示,包括符号位,表示为010000000,超过了2个字节,如果截取低8位,那么是10000000,最高位(符号位)是1,表示的是一个负数了!我们再看看-128的机器码是多少,原码110000000,反码101111111,补码110000000,截取低8位即10000000,表示的是一个负数。)

补码的加减运算如下:
( 1 ) 10- ( 1 ) 10= ( 1 )10 + ( -1 )10 = ( 0 )10
(00000001)补 + (11111111)补 = (00000000)补 = ( 0 ) 正确
( 1 ) 10- ( 2) 10= ( 1 )10 + ( -2 )10 = ( -1 )10
(00000001) 补+ (11111110) 补= (11111111)补 = ( -1 ) 正确
所以补码的设计目的是:
⑴使符号位能与有效值部分一起参加运算,从而简化运算规则.
⑵使减法运算转换为加法运算,进一步简化计算机中运算器的线路设计
所有这些转换都是在计算机的最底层进行的,而在我们使用的汇编、C等其他高级语言中使用的都是原码。看了上面这些大家应该对原码、反码、补码有了新的认识了吧!



Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐