补码取反加一是原码
原码取反加一是补码
求大神解释一下
这其实只是原码和补码表示的意义所使然的。简单的说,可以想想在二进制表示中,即存在一个 +0 还存在一个 -0,那在直接取反的过程中,其实就自动少了 1,这时候要加 1 才能保证再次取反能回归原数(再次取反时又会少一,还得加)。
以8位二进制为例。
根据定义,正数a的反码就是原码,-a的反码是a的原码高位取1,其他位求反(就是a的反码所有位求反)。所以a和—a的反码所有位都不同。如果把他们都当做无符号二进制数,则他们的和等于(11111111)b,也就是255。因此 a反+1=256-a
。做两次这样的操作就是256-(256-a)=a
,也就是你说的可逆的:这仅仅是是一个逆函数是自身的普通函数而已。
至于为什么使用补码来表示数字? 8bit二进制数,一共有256种情况,我们使用 0...255表示,所以只能表示 256个整数,当我们需要有符号数的时候,就只能表示 -128~127。其实,用0表示-128,1表示-127,....,255表示127,就挺好的了(满足所有合理的数学运算)。可是这种方式总是不符合人类的习惯,人们还是习惯0表示0....。
所以,我们要求可以满足四条:1、线性映射(规则简单);2、合理的处理计算溢出的情况;3、计算机处理起来方便;4、符合人类的习惯;
所以最终方案是:0~127 用 0~127 表示, -128~-1 用 -128~-1 + 256 = 128~255
来表示。原码,反码,补码的概念就是人们在设计数字电路的时候,优化这个+256
的时候出现的概念。总结一下就是 正数的补码是原码
,负数的补码就是 负数+256
的原码。
这仅仅是模256
的加法群的一个同构群。加运算就是(补码对应的二进制正整数)结果的补码=(补码1+补码2)MOD 256
。因此即使溢出了也仅仅是与正确的结果相差256的整数倍。
取反加1
更多的是根据转换规则总结出来的“口诀”,所以要理解为什么,还是要搞清楚补码和原码之间是如何转换的。
补码的定义是:模-原码
,模是2^(n-1),这里n为数的位长。例如对于8位的单字节有符号整数来说,补码=2^7-原码
。(因为8位有符号数的最高位为符号位,所以实际上用来表示数的绝对值大小的只有7位)
为了便于理解,下面的计算都以8位数来做例子,就不用别扭的n来表示了。
模 = 2^7 = 10000000 (1后面7个0)
而:原码+反码 = 1111111 (7个1) = 2^7 - 1
移项:2^7 - 原码 = 反码 + 1
等式左边正好是补码的定义,所以补码自然就是反码+1了
这就是补码=原码取反+1
的来历。再来看看怎么用补码求原码。
因为:补码 = 反码 + 1
所以:反码 = 补码 - 1
两边同乘以-1,并且同时加上1111111(7个1):
1111111 - 反码 = 1111111 - 补码 + 1
等号左边正好是原码,等号右边的“1111111 - 补码”部分正好是“补码的反码”,所以:
原码 = 补码的反码 + 1
因此原码=补码取反+1
。
题主的说法是有问题的
取法加一其实就是对任意数A, 取-A的补码形式
先假定任意数A为八位.
取反加一实际上11111111 - A(补) + 1 = 100000000 - 1 - A(补) + 1 = 100000000 - A(补) = 0 - A(补) = (-A)(补)
一定要认清数和编码之间的区别,不然很容易混淆
只是进位之后会消除。
设原码为A
,用N
位二进制数字表示。则:
取反后得:
2^N-1-A
;(这一步是因为反码和原码的和是2^N-1
得到的)加一后得:
2^N-A
,即补码,记为B
;再取反后得:
2^N-1-B
,即2^N-1-(2^N-A)
即A-1
;再加一后得:
A
。
完毕。
以上证明了:~(~A+1)+1=A
。
其实可以这样理解:
首先
~(~A)=A
很好理解吧,因为一个数取反两次肯定等于原数嘛。然后两次加1,分别是在取反一次后和取反两次后进行的。所以两次性质相反,相当于一次是
+1
一次是-1
,抵消了。推广一下就是:
~(~A+M)+M=A