在计算机系统中,数值一律用补码来表示和存储。——百度百科
首先要明确一个前提:人类是喜欢简单的,他们不希望增加硬件复杂度以求得全面的运算体系,如计算机既做加法,也做减法,如果分开做,那么必然会增加硬件成本,这是我们刻意避免的,那么怎么来解决这个问题呢?
答:采用一种巧妙的编码方式,使得计算机做减法和加法是一样的硬件电路,我们采用的方法是二进制串的首位不再表示数值,而是表示正负,从而使得符号位和数值位可以统一处理,即不用计算机辨别是加还是减,总之一起运算保证得到正确的结果就好了。
现在问题来了,我们该用怎样的编码方式呢?首先想到的一种编码方式自然是符合人类直觉的叫做原码(这是我们后来给它起的名字)的东西,那我们就来看一看原码能不能完成任务:
计算十进制的表达式: 1-1=0
1 - 1 = 1 + (-1) = [00000001]原
+ [10000001]原 = [10000010]原 = -2
如果用原码表示, 让符号位也参与计算, 显然对于减法来说, 结果是不正确的.那么原码的编码方式是不行的,为了解决原码做减法的问题, 出现了反码:
计算十进制的表达式: 1-1=0
1 - 1 = 1 + (-1) = [0000 0001]原
+ [1000 0001]原= [0000 0001]反 + [1111 1110]反 = [1111 1111]反 = [1000 0000]原 = -0
发现用反码计算减法, 结果的真值部分是正确的. 而唯一的问题其实就出现在"0"这个特殊的数值上. 虽然人们理解上+0和-0是一样的, 但是0带符号是没有任何意义的. 而且会有[0000 0000]原和[1000 0000]原两个编码表示0.
于是补码的出现, 解决了0的符号以及两个编码的问题:
1-1 = 1 + (-1) = [0000 0001]原
+ [1000 0001]原 = [0000 0001]补 + [1111 1111]补 = [0000 0000]补=[0000 0000]原
这样0用[0000 0000]表示, 而以前出现问题的-0则不存在了.那么-0哪里去了呢?给-128了!!
(-1) + (-127) = [1000 0001]原
补码的编码方式解决了困扰我们的问题,使得数值计算不再用分辨符号位了,只需要指明一个数是有符号数,计算机就会自动把其首位认为是符号位,然后对其进行补码转换(不管是正数还是负数,但是正数的补码是其本身),用补码进行运算,得到的运算结果也是补码,看其符号位就知正负,如果是0,则不用再求其补码(正数的补码是其本身);如果是1,则需对其求补码,可以得到实际的符合人类直觉的数值(负数的补码是看不出来其确切数值的,需要再对其求补,对-128不适用此法则)——补码的补码是原值(对于负数而言)。
下一个问题,补码这种编码方式是怎么被发现或者创造的?巧合么?
答案是NO!补码的编码方式起源于模的概念,
而且实际上并不是从10000001到11111111依次表示-1到-127,而是刚好相反的,从10000001到11111111依次表示-127到-1.