17th
计算机如何做减法?
在计算机中,减法也是通过加法器实现的,因为减一个数相当于加这个数的相反数,比如 10 减 5 相当于 10 加 -5。于是就产生了另外一个问题,计算机怎么表示有符号数。目前普遍采用的方案是补码。我们都知道,如果计算机是 n 位的,那么它能表示的整数范围是 $-2^{n-1} \sim 2^{n-1}-1$,补码的思想是,在表示有符号整数时,用 $0 \sim 2^{n-1}-1$ 表示他们自身,用 $2^{n-1} \sim 2^n-1$ 表示 $-2^{n-1} \sim -1$。
这就可以解释为什么补码表示的负数都是以 1 开头的,并不是因为 1 是符号位,而因为范围在 $2^{n-1} \sim 2^n-1$, 表示负数的这些数,恰好都是以 1 开头。
举个例子,假设有一台 4 位的计算机,那么它能表示的有符号整数的范围是 $-2^{3} \sim 2^3-1$,即 $-8 \sim 7$,那么在补码系统中,其实是用 $8 \sim 15$ 来分别表示 $-8 \sim -1$。比如 -8,用补码表示是 1000,如果单拎出来二进制的 1000,而不考虑其他意思,是不是就是十进制的 8?再比如 -5,用补码表示是 1011,而实际上单纯二进制的 1011 等于十进制的 11。
在十进制中:-8 + 3 = -5
用补码表示就是:1000 + 11 = 1011
而如果我们把上面这个二进制等式直接换算成十进制,不考虑补码,不就是 8 + 3 = 11 吗?
这样就完美地把加法和减法统一起来了。
再看一个现象,在 4 位的计算机中,-1 应该是用 15 来表示,即 1111,1111 + 1 = 10000,由于这台计算机只有 4 位,所以最左边的 1 溢出了,只剩下 0000,也就是 0,刚好满足 -1 + 1 = 0。
所以为什么在 Java 中,Integer.MAX_VALUE + 1
会等于 Integer.MIN_VALUE
,因为`Integer.MAX_VALUE
的值是 $2^{31}-1$,而虽然 Integer.MIN_VALUE
的值是 $-2^{31}$,但其实在计算机底层是用 $2^{31}$ 表示的,$2^{31}-1+1$ 不就是等于 $2^{31}$ 嘛。
使用补码还有一个好处是,对于涉及正数和负数的加法,我们可以根据计算结果的符号位来判断是否溢出。一般来说,如果两个操作数的符号位相同,但结果的符号位不同,那么可以认为结果是溢出的。
Last updated
Was this helpful?