瞎谈补码
补码是什么?记得C语言课本上写的,负数补码就是反码+1。很简单的一句话,但是讲的不明不白的。 为什么负数补码是反码+1? 为什么正数的补码是其本身? 为什么127下一个数是-128? 下面拿一个字节来扯淡。 正数的编码是其本身 在计算机里,全部都是用补码表示数,补码就是一种对数的编码规则,一个二进制数就是一个code point,类似于unicode是一种字符的编码规则,一个code point可以对应一个真值。包括原码和反码,都是一种编码。所以这可以解答第二个问题,因为在补码里,我们把二进制0000 0000规定为0,最高位0的编码为正数,所以正数的补码是其本身,更确切的说法,在补码中,正数的编码是其本身。 所以8bit的范围是[-128,127],当然我们可以规定8bit的范围是[-129,126],或者[-127,128]这样做的后果就是:正数的编码不是其本身。 这会导致什么呢,我觉得这不会导致什么,无非就是对二进制认知会出现点问题,比如代码里写byte a = 1;,那么我们期望得到00000001,但是如果编码不是[-128,127],那么我们声明的byte就不是我们期望的二进制序列——我们得按编码规则然后推出00000001对应的真值是多少,然后才能正确赋值。但是从计算的角度来说,只要编码确定了,计算就不会出错。 原码和反码 有很多谈补码的,有一个观点是补码是在反码的基础上设计出来的,再加上这句负数补码是反码+1,就似乎更是如此了。 但是这有点由果推因的味道。反码英文是1's complement,称“1补数”,补码是2's complement,称“2补数”,其中complement的意思就是补码(后续补码单指2's complement),所以这两种码应该是不能看作依赖关系的,只能说两者之间可以互相推导。 从原码开始说起,原码是这么编码的:最高位是符号位,0是正数,1是负数,其他表示绝对值。但是对计算机来说,还得判断最高位才能计算,不行🙅。 反码是最高位作为符号位,负数保留符号位1不变,剩下位按位取反。反码只是为了让符号位参与计算,计算结果和真值计算结果相比,时对时错,其中根本问题是有两个0(+0/-0),这需要通过循环进位的规则才能正确应用。 要正确应用反码,运算规则是,如果最高位产生进位,要把进位循环进位到最低位。比如0100 1000 + 1100 1000进行计算,结果是1 0001 0000,那么在模=2^8的情况下最终结果应该是0001 0001。我的理解是,最高位进位,说明越过了(+0/-0),是少一个数的,需要+1来调整。 Internet协议IPv4,ICMP,UDP以及TCP都使用同样的16位反码检验和算法。虽然大多数计算机缺少“循环进位”硬件,但是这种额外的复杂性是可以接受的,因为“对于所有位(bit)位置上的错误都是同样敏感的”。 在UDP中,全0表示省略了可选的检验和特性。另外一种表示:FFFF,指示了0的检验和。 (在IPv4中,TCP和ICMP都强制性地规定了检验和,而在IPv6中可以省略)。 补码 补码系统利用了模的思想,模就是用来表示一个计数范围,比如⏰的计量范围是0~11,模=12。二进制0000 0000~1111 1111的模就是1 0000 0000。 上面说到模,补码系统就是这么规定:一个数和他的二补码之和等于模。在8位数中,1 0000 0000和0的值是等价的,所以一个数和他的二补码之和等于0,那么,一个负数在补码系统里可以用正数的二补码来表示。同时可以得出一个结论,求一个数的相反数,只要求他的二补码就好了。 由于n的二补码=(模 - n)=(1 0000 0000 - n)=1 + 1111 1111 - n,1111 1111 - n刚好又是按位取反,是反码,所以一个数的二补码是反码+1。但这只能作为一个定理,不能作为定义。-128不适用“负数补码是反码+1”,但是,在补码系统里,这个数却是存在的。事实上,-128的二补码等于其本身。 编码是有序的 在我看来,二进制没有正负之分,这个正负是人为加上去的,机器并不需要知道当前的数的正负。他只要拿到0000 1000和1111 1101相加,得到0000 0101,那么这个0000 0101是表示什么,机器不感兴趣。所以说即使8bit的范围变成[-129,126]或者[-127,128],也不影响结果,只要编码是有序的,二进制计算法则总能保证结果是正确的(当然,这就不是补码了)。 这里的有序,指的是二进制的顺序和真值的顺序是一致的。比如不可以规定{01111 1111,0111 1110,...,1000 0001,1000 0000}对应[-128,127],这样二进制顺序和真值顺序不一致。 像原码,-15 -> -14,其编码1000 1111->1000 1110,这是不按顺序的。反码大致保证了顺序,但是存在两个0的code point,需要引入额外的调整才能消处两个0的问题。...