概述
转自:百度百科https://baike.baidu.com/item/%E8%A1%A5%E7%A0%81/6854613?fr=aladdin
整数补码
编辑
求给定数值的补码分以下两种情况:
正数
正整数的补码是其二进制表示,与原码相同 [2] 。
【例1】+9的补码是00001001。(备注:这个+9的补码是用8位2进制来表示的,补码表示方式很多,还有16位二进制补码表示形式,以及32位二进制补码表示形式,64位进制补码表示形式等。每一种补码表示形式都只能表示有限的数字。)
负数
求负整数的补码,将其对应正数二进制表示所有位(除符号位)取反(0变1,1变0,符号位为1不变)后加1 [2] 。
同一个数字在不同的补码表示形式中是不同的。比如-15的补码,在8位二进制中是11110001,然而在16位二进制补码表示中,就是1111111111110001。以下都使用8位2进制来表示。
【例2】求-5的补码。
-5对应正数5(00000101)→所有位取反(11111010)→加1(11111011)
所以-5的补码是11111011。
【例3】数0的补码表示是唯一的。
[+0]补=[+0]反=[+0]原=00000000
[ -0]补=11111111+1=00000000
转化为原码
已知一个数的补码,求原码的操作其实就是对该补码再求补码:
⑴如果补码的符号位为“0”,表示是一个正数,其原码就是补码。
⑵如果补码的符号位为“1”,表示是一个负数,那么求给定的这个补码的补码就是要求的原码。
【例4】已知一个补码为11111001,则原码是10000111(-7)。
因为符号位为“1”,表示是一个负数,所以该位不变,仍为“1”。
其余七位1111001取反后为0000110;
再加1,所以是10000111。
补码的绝对值
【例5】-65的补码是10111111
若直接将10111111转换成十进制,发现结果并不是-65,而是191。
事实上,在计算机内,如果是一个二进制数,其最左边的位是1,则我们可以判定它为负数,并且是用补码表示。
若要得到一个负二进制补码的数值,只要对补码全部取反并加1,就可得到其数值。
如:二进制值:10111111(-65的补码)
各位取反:01000000
加1:01000001(+65)
小数补码求法
编辑
一种简单的方式,符号位保持1不变,数值位从右边数第一个1及其右边的0保持不变,左边按位取反。
代数加减运算
编辑
补码加法
[X+Y]补 = [X]补 + [Y]补
【例6】X=+0110011,Y=-0101001,求[X+Y]补
[X]补=00110011 [Y]补=11010111
[X+Y]补 = [X]补 + [Y]补 = 00110011+11010111=00001010
注:因为计算机中运算器的位长是固定的(定长运算),上述运算中产生的最高位进位将丢掉,所以结果不是100001010,而是00001010,。
补码减法
[X-Y]补 = [X]补 - [Y]补 = [X]补 + [-Y]补【1】
【例7】1-1 [十进制]
1的原码00000001 转换成补码:00000001
-1的原码10000001 转换成补码:11111111
1+(-1)=0
00000001+11111111=00000000
00000000转换成十进制为0
0=0所以运算正确。
【例8增】-7-(-10) [十进制]
改为加法形式:-7-(-10)=-7+(-(-10))
-7的补码:11111001
-(-10)的补码:-10的原码为10001010,-(-10)的原码为00001010,
-(-10)的补码就是其原码,为00001010
-7 - (-10)= -7 + 10 = 3
11111001+00001010 = 00000011
转换成十进制为3
补码乘法
补码的乘法不具备【X*Y】补=【X】补×【Y】补的性质。但是【X*Y】补==【X】补×Y,所得结果再取补码,如x=101,y=011,[x*y]补=-[(-101)*011]=-[011*011]=-01001=10111
其中,若【Y】补=y31y30……y0,则 Y=-y31*2^31+y30*2^30+……+y0*2^0
代数解释
编辑
在十进制中我们可以把n位二进制体系中的数
a表示为:
求补码,意味着求:
而根据等比数列求和公式:
则
因为这里k0,k1,k2,k3……不是0就是1,所以1-k0,1-k1,1-k2的运算就是二进制下的取反
注:n位二进制,最高位为符号位,因此表示的数值范围-2^(n-1) ——2^(n-1) -1,所以模为2^n。上面提到的8位二进制模为2^8是因为最高位非符号位,表示的数值范围为0——2^8-1。
补码总结
编辑
补码只是一种相对合理的编码方案。这个方案在负数的机器表示中解决了3个问题:
-
数的表示
在数的表示上通过人为的定义来消除编码映射的不唯一性,对转换后的10000000强制认定为-128。当然对原码和反码也可以做这种强制认定,那为什么原码和反码没有流行起来?原码和反码没有流行起来,是因为在数的运算上对符号位的处理无法用当时已有的机器物理设计来实现。由于原码和反码在编码时采用了硬性的人工设计,这种设计在数理上无法自动的通过模来实现对符号位的自动处理,符号位必须人工处理,必须对机器加入新的物理部件来专门处理符号位,这加大了机器设计难度,加大的机器成本,不到万不得已,不走这条路。
-
数的运算
设计补码时,有意识的引用了模运算在数理上对符号位的自动处理,利用模的自动丢弃实现了符号位的自然处理,仅仅通过编码的改变就可以在不更改机器物理架构的基础上完成的预期的要求,所以补码沿用至今。
-
自身逻辑意义的完整性
补码这个编码方案要解决的是如何在机器中表示负数,其本质意义为用一个正数来表示这个正数对应的负数。所谓-20的补码是指:如何在机器中用补码形式表示-20。具体过程是这样的:将20的二进制形式直接写出00010100,然后所有位取反变成11101011,再加1变成了11101100。最简单的补码转换方式,不必去理会转换过程中的符号位,只关注转换前和最终转换后的符号位就行了。
那么对11101100求出其补码又具有什么现实含义呢?对一个数求补,逻辑过程是对这个数的所有的二进制位按位取反再加1。现实含义是求出这个数对应的负数形式。对11101100求补就是求出这个数对应的负数的形式,直接操作下11101100,先所有位取反00010011,再加上1就成了00010100。对11101100求出其补码的含义:11101100按照现行补码码制表示的有符号数是-20,对于-20求补就是求出其对应的负数-(-20),现实中-(-20)是+20,那么求补运算的结果符合现实情况吗,00010100转换成有符号数正是+20,这就说明了补码自身逻辑意义是完整的,是不会自相矛盾的。
-
最后,补码的总前提是机器数,不要忘了机器数的符号位含义,最高位为0表示正数,最高位为1表示负数,而最高位是指机器字长的最左边一位。字节数100B,最高位为00000100中的最左边的0。
【1】 在上一个版本中有如下说明:
“其中[-Y]补 称为负补,求负补的方法是:负数的绝对值的原码所有位按位取反;然后整个数加1。(恢复本来解释。请路人真正理解并实际验证后再修改。以免误导大众。另外,例6不具典型性,新增例7。)”
私以为, 不必要提出负补的概念以使问题复杂化,尽管该解法是正确的,但却完全没有必要增加新的运算方法及运算结构。求[-Y]补,只需,先将符号位取反,求出-Y, 再求-Y的补码即可。尽管这与求负补的方法实际上是一致的, 但是却简化了概念,仅仅是对过去概念以及运算结构的复用。
一下转自:https://www.cnblogs.com/PI3141592657/p/7134474.html
什么是Complement(补码)?
大学上过计算机原理课程的朋友都接触过补码这个概念,不过当时书上所教授的内容都是以二进制作为前提,即所谓的2的补码(2's Complement)。近来看TCP/IP Volume 1时,又接触到“1的补码”这个概念,忽然发现其实还不太明白补码到底是什么意思,故查阅资料记录之。
资料来源:维基百科
术语解释:Radix —— 基数,在本篇文章的范畴内等价于“进制”
定义:给出长度为n的数值y,则y的以基数b的补码为: bn - y (即 b的补码)
水平有限,翻译的比较拗口,不过公式还是很简洁的,实际上补码从定义上来说并没有什么难懂的地方。不过有些地方需要加以说明,补码这个概念是建立在进制(即基数)的基础上的,至少在计算机科学的术语中,补码定义中的基数b是一定等于当前进制的,也就是说以上定义可以简化为
给出长度为n的数值y且该数值为b进制,则y的补码为: bn - y
下面以十进制的数作为例子
给出数值y = 1234,很明显长度n = 4,基数b = 10(你说不知道10从哪来的?论审题的重要性)
根据补码的定义那么 y的补码为:104 - 1234 = 8766
用途:补码的作用是什么呢?你走运啦,补码的用途很专一 —— 用加法操作来代替减法操作
听起来匪夷所思,你几乎要脱口而出:“不可能!!!”,不过按照国际惯例,我们先来看看到底怎么回事吧
这里要引入另一个很简单但是英文又很有bigger的术语: 缩小基数补码 (diminished radix complement),看到 diminished 这个词我立马打个激灵,想起了久未谋面的缩小增量排序(diminished increment sort),啥?你说老师没教过这个?噢,它的另一个名字叫希尔排序,它是。。。咳咳,不好意思跑题了。
缩小基数补码实际上就是 (bn - 1) - y,就是说你可以通过往缩小基数补码上加个 1 来得到基数补码,也就是说
bn - y = (bn - 1) - y + 1
是不是想大喊一声:这TM不是废话么??
这个概念有什么用?其实在纯数学的范畴内,这个纯属多余,没有任何用处。然而到了我这个年纪,就会明白一切看起来无意义的东西,肯定一定必须存在一个让它拥有意义的上下文环境。在本文内,这个环境就是“一个数值的长度”,你要知道在数学范围内,你想把一个数写多长就有多长,但是在计算机内数值长是固定的,譬如Java语言的int数值长度为32位,你无法用32位的数去表示33位数,当然34位就更不行了!
回到基数b这个关键字上面来,还是以十进制数为例子
假设数值长度为固定的4,给出数值y = 1234,如果说你真的要按照定义在计算机内去获得补码,你是做不到的,因为根据定义补码为104 - 1234,然而104 = 10000,已经超出了4位数所能表示的范围,你明白了么?缩小基数补码就是为了能在固定的数值长度中去获得补码,所以退一步海阔天空啊
- 104 - 1 = 9999
- 9999 - 1234 = 8765
- 8765 + 1 = 8766
然而,聪明如你一定发现了,说是补码的用途是用加法代替减法,可是在以上第二步获得补码的关键步骤里,不还是要进行减法??这有毛区别?哈,这个就是最让人兴奋的地方,在二进制世界里,你不需要再用减法了,下面以二进制为例子
给出数值y = 1011,那么很明显,按照最新的补码求解步骤,补码 = ( 24 - 1 ) - 1011 + 1,猛然一看,这哪里履行了补码的承诺,用加法代替减法?那么我们就以二进制的视角去看
y = 1011
24 - 1 = 1111
实际上你已经发现了,这个缩小基数补码是固定的——给定计算机数值长度n,则缩小基数补码可以直接写出:pppp...ppp(n个p,p = 进制 - 1),而关键的
1111 - 1011,这一步实际上已经不需要作减法操作了,直接对 y 取反再加上 1 就能得到补码了(是不是对“取反加一”感到特别耳熟?你是个上课听课的好孩纸),在此不得不感谢伟大的二进制!需要再次声明下,这么流畅的操作只有二进制能完成,其他进制想要获得补码,依然需要减法。
终章:在神奇的二进制世界中,获得一个数的补码只需要简单的取反再加上一就可以了。那么最后我们来看看,补码到手之后,又怎么能代替减法呢?
假设需要求解 x - y ( x >= y),那么分为以下步骤
- 求得y的补码 bn - y
- x - y = x + ( bn - y ) = x - y + bn (这一步用补码的加法代替了原数值的减法)
- 显然 x - y + bn >= bn,然而bn已经超出了数的表示范围(overflow),直接被丢弃了,最后的结果就等于x - y
1的补码:这个世界是没有1进制的,所以1的补码是一个缩小基数补码,也就是直接对一个二进制数值取反
最后
以上就是迷人跳跳糖为你收集整理的补码什么是Complement(补码)?的全部内容,希望文章能够帮你解决补码什么是Complement(补码)?所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复