赞
踩
本文帮助理解,Java中原码反码补码的原理
对于一个数,计算机需要使用一定的编码方式进行存储。原码反码补码是计算机存储一个具体数字的编码方式。
原码:
第一位表示符号位,其余位表示真值
[+1]原 = 0000 0001
[-1]原 = 1000 0001
反码:
正数的反码跟原码相等
反码计算:在符号位不变的基础上,其余各位取反
补码:
正数的补码跟原码相等
补码计算:在反码的基础上,最后加1
1:利用反码和补码能将符号位带入计算(简化计算机门电路的设计,利用加法运算代替减法运算 1 - 1 = 1 + (-1) )
// 利用反码进行计算
1 - 1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原= [0000 0001]反 + [1111 1110]反 = [1111 1111]反 = [1000 0000]原 = -0
// 利用补码进行计算,可以解决反码中的 -0的问题
1-1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原 = [0000 0001]补 + [1111 1111]补 = [0000 0000]补=[0000 0000]原
2:意外收获,利用补码进行计算 ,可以表示 -128(注意:-128没有反码和原码表示)
(-1) + (-127) = [1000 0001]原 + [1111 1111]原 = [1111 1111]补 + [1000 0001]补 = [1000 0000]补
因为机器使用补码, 所以对于编程中常用到的32位int类型, 可以表示范围是: [-2^31, 2^31 - 1] 因为第一位表示的是符号位.而使用补码表示时又可以多保存一个最小值.
利用补码来进行计算,可以推算出下面的等式成立
Integer.MAX_VALUE + 1 = Integer.MIN_VALUE Integer.MIN_VALUE - 1 = Iegnter.MAX_VALUE
计算机巧妙的把符号位参与到运算中,并且把减法变成加法。
把钟表想象成一个1位的12进制数,如果当前时间是6点,我希望将时间设置成4点,有如下的操作可以达到目的
1:往回拨2h 6 -2 = 4
2:往前拨10h (6 + 10)mod 12 = 4
3:往前拨 10 + 12 = 22h (6 + 22) mod 12 = 4
从上面可以看出,钟表往回拨(减法)的结果可以用往前拨(加法)来代替
两个整数a,b,若他们除以整数m所得的余数相等,则称a,b对于模m同余,记作 a = b(mod m)。读做a与b关于模m同余
eg:4 , 16 , 28 关于模12同余
4 mod 12 =4
16 mod 12 = 4
28 mod 12 = 4
eg:
-3 mod 2 = -3 - 2 * (-3/2)
= -3 - 2 * (-2)
= -3 + 4 = 1
(-2) mod 12 = 10
10 mod 12 = 10 -2 和 10是同余的
线形运算定理:
如果a ≡ b (mod m),c ≡ d (mod m) 那么:
(1)a ± c ≡ b ± d (mod m)
(2)a * c ≡ b * d (mod m)
如果想看这个定理的证明, 请看:http://baike.baidu.com/view/79282.htm (同余定理)
现在我们为一个负数,找到了它的正数同余数,7 -2 ≡ 7 + 10 (mod 12) 即计算结果的余数相等
下面回到二进制的问题上,看一下 2 - 1 = 1 的问题
2-1=2+(-1) = [0000 0010]原 + [1000 0001]原= [0000 0010]反 + [1111 1110]反
先到这一步, -1的反码表示是1111 1110. 如果这里将[1111 1110]认为是原码, 则[1111 1110]原 = -126, 这里将符号位除去, 即认为是126.
发现有如下规律:
(-1) mod 127 = 126
126 mod 127 = 126
即:
(-1) ≡ 126 (mod 127)
2-1 ≡ 2+126 (mod 127)
2-1 与 2+126的余数结果是相同的! 而这个余数, 正式我们的期望的计算结果: 2-1=1
所以说一个数的反码, 实际上是这个数对于一个模的同余数. 而这个模并不是我们的二进制, 而是所能表示的最大值! 这就和钟表一样, 转了一圈后总能找到在可表示范围内的一个正确的数值!
而2+126很显然相当于钟表转过了一轮, 而因为符号位是参与计算的, 正好和溢出的最高位形成正确的运算结果.
既然反码可以将减法变成加法, 那么现在计算机使用的补码呢? 为什么在反码的基础上加1, 还能得到正确的结果?
2-1=2+(-1) = [0000 0010]原 + [1000 0001]原 = [0000 0010]补 + [1111 1111]补
如果把[1111 1111]当成原码, 去除符号位, 则:
[0111 1111]原 = 127
其实, 在反码的基础上+1, 只是相当于增加了膜的值:
(-1) mod 128 = 127
127 mod 128 = 127
2-1 ≡ 2+127 (mod 128)
此时, 表盘相当于每128个刻度转一轮. 所以用补码表示的运算结果最小值和最大值应该是[-128, 128].
但是由于0的特殊情况, 没有办法表示128, 所以补码的取值范围是[-128, 127]
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。