计算机中的加减法(原码、反码、补码)
假设我们的计算机比较低级,只能计算4个bit(位)的数。原码4个bit可以存下多大的数?只存正数如果我们只存正数,可以表示的范围是0000-1111,也就是0 至 15,一共可以存16个数。既存正数,也存负数如果我们继续要存正数,也需要存负数,就需要用一个bit来表示符号位。假设约定用最高位表示符号位,1表示负数,0表示正数。则范围变成了 1111-0111,也就是 -7至 7,一共可以存15个数
假设我们的计算机比较低级,只能计算4个bit(位)的数。
原码
4个bit可以存下多大的数?
只存正数
如果我们只存正数,可以表示的范围是0000-1111,也就是0 至 15,一共可以存16个数。
既存正数,也存负数
如果我们继续要存正数,也需要存负数,就需要用一个bit来表示符号位。
假设约定用最高位表示符号位,1表示负数,0表示正数。
则范围变成了 1111-0111,也就是 -7至 7,一共可以存15个数。
为啥只能存15个数了呢,因为此时 1000 与 0000都表示0,重复了。
加法
我们做一个在取值范围内的加法运算,似乎很轻松,结果也没有问题。
减法
a - b = a + (- b)
其实两个正数的减法也可以转化为 正负数相加。
做一个简单的正负数相加运算: -2 + 1
结果居然是-5,很明显不正确。
转换思路
对于计算机来说“负数”这个概念太复杂了,我们换个角度来思考这个问题。
文章的开头有一个限制,我们的计算机只能存储4个bit的数,如果超过4个bit,则会忽略高位。
现在是夜里11点,我的闹钟了指向了11,两个小时候时针会指向13吗?自然不会,两个小时后指针指向1。
那么在时钟的世界里,就可以用 (11 + 2)来表示 (11 - 10)。
这就是一个从减法转化为纯粹正数相加的过程。发现规律没? 2 + 10 = 12 刚好是时钟的“容量”
知道这个方法后,我们再来计算 -2 + 1,怎么把他转化为两个正数相加呢。
(!注意,这个时候我们别去考虑什么符号位,我们的目的是彻底转化为两个正数相加)
4个bit如果都用来存正数,可以存16个,容量就是16。
16 - 2 = 14
14的二进制是 1110
结果是1111,也就是15,我们期望的结果应该是 - 1,即使把最高位看作是符号位,结果也不对,肯定还需要一个转化的过程。
假设我们的这种方法是对的,我们还需要解决两个问题。
1、-2(1010)是怎么转化到 1110的。
2、我们获得结果1111怎么转化为最种结果1001(-1)。
这就需要引入反码和补码的概念了。
反码
我们人类看的懂的是原码,计算机看得懂是补码,反码就显得格外没有地位。
确实,反码只是原码转化为补码的一个中间产物,只是用来过度的。
正数的反码 = 正数的原码
负数的反码 = 负数的原码 除符号位外,全部取反
补码
正数的补码 = 原码
负数的补码 = 反码 + 1
-2 的原码1010,取反加1后,得到1110,解决了第一个问题。
我们之前运算得到的值是1111,尝试对这个数取补码,得到 1001。
1001不正是我们需要的结果 -1 吗?解决了第二个问题。
总结
计算机是很“单纯”的,只会做正数的加法,他不懂什么是负数,什么是减法。
但我们可以利用它的特点——如果计算结果超过了存储的范围,则丢弃溢出的数。引入补码的概念,彻底将减法转化为加法。
之前写的 &0Xff,也是类似的思想,有兴趣可以看看:
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)