- 计算机中,存储数据是使用一个数字的二进制的补码进行的。
- 为什么这么设计,这是一个好的问题。不知道你的大学老师有没有给你讲清楚。
- 我搞了一下,讲给你听:
- 首先,计算机是只能存储0和1的,并且计算机的0和1,都是用低电平、高电平表示。也就是想象一下,有这么几个坑,有的有电,有的没有电。要进行计算的时候,只能向这个坑里进行填充,比如再放进去一个高电平,或者放进去一个低电平(相当于没放)。而没有办法从里边拿出来一个高电平。
- 所以说,计算机只能做加法,而不能做减法。
- 那么,我们要做减法的时候怎么操作呢,因为是有这个数学概念的呀。人们就想了一个办法,把要减去的那个数字,表示成一个负数,这样,减法就变成了加上一个负数。关键,什么是负数呢?就是欠着。
- 比如你要减去75,那就等于加上一个负的75.什么是-75呢,就是借给你100,这时候,你是不是就-100了?然后你再给上25,这时候是不是就欠75了?所以,我们就用 (-100 + 25 )这样的组合,去表示-75.
- 这样有什么好处呢?比如,我现在是80,我现在要减去75,应该怎么做? 首先,我先借100,记着,不用操作。然后,我还上25,也就是80+25,这时候,结果是多少? 105对不对,之前还借了100呢,这回有了,还账吧,105-100=5.这就是结果。
- 那位说,这不还是做了减法吗?可以说,这个100是虚拟的,之前借就是记着,没操作,那么后面这个减100的操作,也可以不做了。忽略掉,怎么忽略呢,就是我们说好,只计算两位数的范围内的加法。如果超了,就忽略掉百位(第三位)数字即可。就是说,借可以但是不要借太多,比如借10000000,没啥意义不是,我们只需要刚好比计算的数字大一位数的最小进位即可。最小进位就是,只需要再加1,就发生进位而产生的那个。
- 同样,计算机里边,虽然是用二进制表示,我们也可以这么干。
- 十进制从百位借一位,表示100. 二进制从百位借一位,表示4. 比如3 要 减 1,我们只需要3+3-4即可。结果就一样是2.后面那个3,就跟上面的25一样,就是找到我们要减去的那个数字的补数。规律就是,一个数字的补数,跟他自己相加,应该会发生进位。如果不考虑进位,那结果就是 0 。
- 而正数的加法,是不需要使用补数的,所以正数的补数,跟他自己是一样的。
- 那么,我们怎样快速找到一个正数的补数呢?
- 我们来看一个二进制数字: 1000 0000,他的补数就是1 0000 0000 - 1000 0000 ,结果是 什么呢?思考,1000 0000 加上多少,才会刚好发生进位? 0111 1111 加上之后,刚好全是1,此时再加一个1,就会发生进位。那么,1000 0000 的补数,就是 (0111 1111 + 1),咦? 刚好,还是1000 0000没有变化啊?
- 认真思考一下,1000 0000 表示的,如果是正数,那么正数的补数,就是他自己。如果它表示的是负数,那么,刚刚好,是 - 0 。负0,正0,也是一样的。
- 所以,补数的获取方式,就是把一个二进制数字,对应是0的位数,全部补成1,1的位数,变成0,这时候,两个数字相加,刚好所有位数全都是1,此时再 + 1,就发生最小进位了。
- 那么,我们把一个二进制数字对应是零的位置设为1,对应是1的位置设为0的操作,叫做取反码。刚好相反的码么。
- 而把这个反码加上1,就成为这个数字的补数。如果要减去这数字,只要加上他的补数,再忽略掉进位就好了。
- 所以,我们默认,计算机里的所有正数原样表示,而把计算机里边的所有负数,都用这个负数对应的正数的补码去表示,这样,要加上一个负数的时候,就只需要加上这个补码,忽略掉进位,就可以完成负数的加法了。
- 而要完成这个操作,又需要有一个借数字的范围,所以我们就需要有一个约定的数据类型,比如,java语言里边,int是使用4个字节去表示一个数字的,表示成二进制,就是32位的一个数字。
- 那么借数的时候,只需要从第33位借就好了。
- 总而言之,我们需要谨记: 计算机中的负数,全部使用其补码形式在内存中,用二进制记录。这样方便与其他正数相加。而正数就不需要使用补码了。
- 所以,负数的补码,等于其反码+1,正数不需要这些。
- 然后还相关的,就是存储范围。
- 比如1个字节,8个bit,0000 0000 —> 1111 1111 范围就是0 --> 255,如果需要表示负数,那么,从1000 0000 - 11111 1111,全都是负数比较特殊的就是这个负零。 因为没有必要使用正零和负零同时表示一个相同的数字。0000 0000 == 1000 0000 ,所以我们把1000 0000 定义为-128. 因为按照正数算,1000 0000 刚好是128,但是因为它的首位(符号位)又是1,所以它应该是负数。
版权归属:
钱学超
许可协议:
本文使用《署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)》协议授权
评论区