浅语
计算机中实现加法是最简单的,所以对于减法都是转化成加法运算的。由计算机的硬件决定,任何存储于计算机中的数据,其本质都是以二进制码
存储。而计算机中底层通常可认为都是使用补码
存储。下面我们来认识下什么是原码
,补码
。
原码、补码,就是为解决,计算机中做减法和引入符号位(正号和负号)的问题。
什么是原码、补码?
1.原码:
- 原码是最简单的机器数表示法。用最高位表示符号位,
1
表示负号,0
表示正号。其他位存放该数的二进制的绝对值。 - 正数的原码,补码表示都是一模一样的,可以认为正数是一种不需要转换的补码,忽略原码这种叫法吧。负数的稍后会谈到。
举个例子:
15的原码就是0000 1111
;-15的原码就是1000 1111
。下图还给出了其他正数负数表示法。
2.补码:
补码是基于反码的变动,有两种情况,如果是正数的补码,就跟原码反码都相同。如果是负数的补码,则在其反码的基础上,再加1。
例:15的补码就是0000 1111
;-15的补码就是1111 0001
。
比如:1的补码就是0000 0001
-1的补码就是1111 1111
为什么计算机用补码表示负数?
解释一:
计算机里,通常用补码表示负数,或者说计算机里只有一种码,那就是补码。
我们偶尔会在有些地方看到这样的说法:计算机有符号数中,正数用原码表示,负数用补码表示。另一种说法是计算机有符号数只有补码一种表示方式。
我个人的理解是都没错,其实也没必要分哪边是正确的叫法,毕竟正数的补码跟原码是完全相同的,如果内容完全一样,那叫法稍有不同也没关系。
我们先假设,计算机的有符号数都是用原码表示的,那么-15就是1000 1111
现在来作个简单的运算,5+(-15)=?
00000101
+10001111
---------
10010100
我们应该要求得的应该是-10,显然1001 0100
的值是-20,它只是把两个数相加,然后再根据符号位判断是正负而已。
如果我们要用原码表示计算机内部有符号数,那就意味着我们不得不再作出另一种运算规则,让正数的相加用一种,跟负数的相加用另外一种。
这是十分复杂的,而现在有更简单的方法,就是引入补码。
解释二:
理解模(Modulo)
模
是指一个计量系统的计数范围。如时钟等。计算机也是一个计算器,它也是有一个计量范围,即都存在一个“模”
- 如时钟的计量范围是0~11,模 = 12。
- 32位计算机的计量范围是2^32,模 = 2^32。
- “模”是计量器产生“溢出”的量,它的值在计量器上表示不出来,计量器上只能表示出模的余数,如12的余数有0,1,2,3,4,5,6,7,8,9,10,11。
补数思想
假设当前时针指向11点,而准确时间是8点,调整时间可有以下两种拨法:
- 一种是倒拨3小时,即:
11-3=8
- 一种是顺拨9小时:
11+9=12+8=8
在以模为12的系统中,加9和减3效果是一样的,因此凡是减3运算,都可以用加9来代替。对“模”12而言,9和3互为补数(二者相加等于模
)。所以我们可以得出一个结论,即在有模的计量系统中,减一个数等于加上它的补数,从而实现将减法运算转化为加法运算的目的。以上就是化减法为加法的思想。
补码原理
计算机上的补码就是算术里的补数。
设我们有一个 4 位
的计算机,则其计量范围即模是2^4 = 16
,所以其能够表示的范围是0~15
,现在以计算 5 - 3
为例,我们知道在计算机中,加法器实现最简单,所以很多运算最终都要转为加法运算,因此5-3
就要转化为加法:
# 按以上理论,减一个数等于加上它的补数,所以
5 - 3
# 等价于
5 + (16 - 3) // 算术运算单元将减法转化为加法
# 用二进制表示则为:
0101 + (10000 - 0011)
# 等价于
0101 + ((1 + 1111) - 0011)
# 等价于
0101 + (1 + (1111 - 0011))
# 等价于
0101 + (1 + 1100) // 括号内是3(0011)的反码+1,正是补码的定义
# 等价于
0101 + 1101
# 所以从这里可以得到
-3 = 1101
# 即 `-3` 在计算机中的二进制表示为 `1101`,正是“ -3 的正值 3(`0011`)的补码(`1101`)”。
# 最后一步 0101 + 1101 等于
10010
因为我们的计算机是 4 位
的,第一位溢出
了,所以我们只保存了 4 位
,即 0010
,而当计算机去读取时这正是我们所期望的 2
!!叹为观止吧,天才般的设计!感恩莱布尼兹
和冯诺依曼
!
👉参考文章: