浅谈补码的原理和正确性

前言

upd 2022.2.14 我就该早点看《计算机组成原理》,补码的定义就是

一个 n n n 位二进制数 N N N 的二进制补码定义为 2 n − N 2^n-N 2nN

不过本文还是严谨证明了它的正确性,以下为原文

补码是怎么来的?

负数的补码为什么是按位取反(除了符号位)再加 1 1 1 ?

补码的正确性能保证吗?

补码背后的数学原理是什么?

本文围绕原理和正确性介绍了补码



一、我们为什么用补码?

我们以 8 8 8 位二进制数为例

8 8 8无符号数,可以表示 0 ∼ 255 0\sim255 0255 以内的数(即 00000000 ∼ 11111111 00000000 \sim 11111111 0000000011111111 ),那么如果我们要表示负数呢?

我们都知道正、负号能够表示正、负数,可是计算机“看不懂“,它只能识别 0 , 1 0,1 0,1

于是,就出现了原码

最高位表示数的正负, 0 0 0 表示 1 1 1 表示

8 8 8有符号数,以原码形式存储则可以表示 0 ∼ 127 0 \sim 127 0127(即 00000000 ∼ 01111111 00000000 \sim 01111111 0000000001111111 ) 和 − 127 ∼ 0 -127 \sim 0 1270 (即 11111111 ∼ 10000000 11111111 \sim 10000000 1111111110000000

相信看到这里,你应该发现了:以原码形式存储时, 0 0 0 的值不唯一

我们把 ± 0 \pm 0 ±0 的问题放一边,先来讨论一下编码的正确性

计算 1 + ( − 1 ) 1+(-1) 1+(1)

00000001 + 10000001 = 10000010 00000001 + 10000001 = 10000010 00000001+10000001=10000010

然而 10000010 10000010 10000010 转成十进制是 − 2 -2 2

由此可知原码不可以直接进行运算,或者可以认为以原码的编码方式运算是错误

那么问题来了,正数的表示都符合我们的习惯,那么问题一定出在负数上


二、补码是怎么来的?

各大教科书上都会告诉你,正数的补码就是它的原码,负数的补码就是原码按位取反(除了符号位)再加 1 1 1

你是不是也很迷惑?补码到底为什么是这么算出来的?

我们还是以 8 8 8 位有符号数为例

我们知道,两个数如果互为相反数则和为 0 0 0 ,例如 1 + ( − 1 ) = 0 1+(-1)=0 1+(1)=0

那么正确的编码方式中 1 + ( − 1 ) 1+(-1) 1+(1) 一定等于 0 0 0

我们设 − 1 -1 1 的编码为 ϕ \phi ϕ ,可得 00000001 + ϕ = 0 00000001 + \phi = 0 00000001+ϕ=0

∴ ϕ = 11111111 \therefore \phi = 11111111 ϕ=11111111(注:计算过程将在下文中讲述,这里只需要知道结果)

那么就很清楚了,如果我们已知编码 ϕ \phi ϕ ,它的相反数的编码就是 0 − ϕ 0 - \phi 0ϕ

现在我们来讨论一下 ± 0 \pm 0 ±0 的问题,显而易见, 10000000 10000000 10000000 肯定是不符合常理的( 00000000 + 10000000 ≠ 00000000 00000000 + 10000000 \ne 00000000 00000000+10000000=00000000

那么 10000000 10000000 10000000 对应的相反数的编码是什么呢?

10000000 + ϕ = 0 10000000 + \phi = 0 10000000+ϕ=0 解得 ϕ = 100000000 \phi = 100000000 ϕ=100000000 (注意位数!)

我们会发现 00000000 ∼ 11111111 00000000 \sim 11111111 0000000011111111 已经无法表示了

0 0 0 呢? 0 0 0 的相反数还是 0 0 0 ,就是它本身

事已至此,干脆就让它们单身着吧。 既然 10000000 10000000 10000000 的第一位是 1 1 1 ,表示负数,那就规定它为负数,因此 10000000 10000000 10000000 就代替了 − 128 -128 128

因为 10000000 10000000 10000000 没有对应的相反数的编码,所以没有 + 128 +128 +128

然后每个数都有了自己对应的编码, 1 ∼ 127 1 \sim 127 1127 对应 − 1 ∼ − 127 -1 \sim -127 1127 ,加上两个单身汉 0 0 0 − 128 -128 128

这种编码就叫补码

那么为什么负数的补码是原码按位取反再加 1 1 1 呢?

我们再看 1 + ( − 1 ) = 0 1+(-1)=0 1+(1)=0 的例子

00000001 + ϕ = 00000000 00000001 + \phi = 00000000 00000001+ϕ=00000000

∴ ϕ = 00000000 − 00000001 \therefore \phi = 00000000-00000001 ϕ=0000000000000001

一个小的数减一个大的数,怎么办?

首先我们应该都知道溢出这一概念

那么 00000000 00000000 00000000 就可以看作 11111111 + 00000001 11111111 + 00000001 11111111+00000001

∴   ϕ = ( 11111111 + 00000001 ) − 00000001 \therefore\ \phi = (11111111 + 00000001) - 00000001  ϕ=(11111111+00000001)00000001

= ( 11111111 − 00000001 ) + 00000001 \qquad= (11111111-00000001) + 00000001 =(1111111100000001)+00000001

注:这个就是简单的结合律

我们看前面一部分,不就是按位取反嘛(反码)!

相信你现在应该理解了,如果我们要求正数 λ \lambda λ 的相反数 μ \mu μ 的补码

μ = ( 11111111 − λ ) + 00000001 \mu = (11111111-\lambda) + 00000001 μ=(11111111λ)+00000001

λ \lambda λ)按位取反(包括符号位)再加 1 1 1 ,当然也是 μ \mu μ 按位取反(除了符号位)再加 1 1 1 ,一样的


三、补码的正确性能保证吗?

1.符号位能保证本身的值、运算结果的值正确吗?

本身的值肯定正确,运算结果的值也正确

运算都是从最低位运算到最高位,这个符号位又加在最高位,不可能影响运算,只可能被影响(注:接下来我们就来证明这个影响不会对运算结果的符号正确性产生影响)

2.数学运算结果的符号能保证正确吗?

为了方便理解和证明,我们以 4 4 4 位有符号数为例(即 − 8 ∼ 7 -8 \sim 7 87

注意:正确性指在数学运算结果不溢出的情况下位运算的结果和数学运算的结果正确

首先,易知任何合法的数 0 0 0 作运算结果一定正确

1) 值的位运算结果不溢出时

1.正数+正数

数学运算结果:一定为正数,符号为

位运算结果:值的位运算不溢出,符号位 0 + 0 = 0 0+0=0 0+0=0,仍为

设这里两个数补码分别为 [ 0 a 2 a 1 a 0 ] , [ 0 b 2 b 1 b 0 ] [0a_2a_1a_0], [0b_2b_1b_0] [0a2a1a0],[0b2b1b0]

A = ∑ i = 0 2 a i × 2 i , B = ∑ i = 0 2 b i × 2 i A = \sum\limits_{i=0}^{2}{a_i\times 2^i}, B = \sum\limits_{i=0}^{2}{b_i \times 2^i} A=i=02ai×2i,B=i=02bi×2i,易知 A , B ∈ N A,B \in \N A,BN

原式可化为 A + B A+B A+B

0 < A + B ≤ 7 0 < A+B \le 7 0<A+B7

值的位运算结果不溢出即 − 8 ≤ A + B ≤ 7 -8 \le A+B \le 7 8A+B7

{ x ∣ 0 < x ≤ 7 } ⫋ { x ∣ − 8 ≤ x ≤ 7 } \{x|0 < x \le 7\}\subsetneqq\{x|-8 \le x \le 7\} {x0<x7}{x8x7}

故该情况 正 确 \color{red}{正确}

2.负数+负数

数学运算结果:一定为负数,符号为

位运算结果:值的位运算不溢出,符号位 1 + 1 = 0 1+1=0 1+1=0 ,变成了

设这里两个数补码分别为 [ 1 a 2 a 1 a 0 ] , [ 1 b 2 b 1 b 0 ] [1a_2a_1a_0], [1b_2b_1b_0] [1a2a1a0],[1b2b1b0]

A = ∑ i = 0 2 a i × 2 i , B = ∑ i = 0 2 b i × 2 i A = \sum\limits_{i=0}^{2}{a_i\times 2^i}, B = \sum\limits_{i=0}^{2}{b_i \times 2^i} A=i=02ai×2i,B=i=02bi×2i,易知 A , B ∈ N A,B \in \N A,BN

原式可化为 − 8 + A + ( − 8 ) + B = − 16 + A + B -8+A+(-8)+B = -16+A+B 8+A+8+B=16+A+B

− 8 ≤ A + B − 16 < 0 ⇒ 8 ≤ A + B < 16 -8 \le A+B-16 < 0 \Rightarrow 8 \le A+B < 16 8A+B16<08A+B<16

值的位运算结果不溢出即 − 8 ≤ A + B ≤ 7 -8 \le A+B \le 7 8A+B7

{ x ∣ − 8 ≤ x ≤ 7 } ∩ { x ∣ 8 ≤ x < 16 } = ∅ \{x|-8 \le x \le 7\}\cap\{x|8 \le x < 16\} = \varnothing {x8x7}{x8x<16}=

故该情况 不 存 在 \color{red}{不存在}

3.一正一负
a.正数绝对值大于负数绝对值

数学运算结果:一定为正数,符号为

位运算结果:值的位运算结果不溢出,符号位 0 + 1 = 1 0+1=1 0+1=1 ,变成了

设这里两个数补码分别为 [ 0 a 2 a 1 a 0 ] , [ 1 b 2 b 1 b 0 ] [0a_2a_1a_0], [1b_2b_1b_0] [0a2a1a0],[1b2b1b0]

A = ∑ i = 0 2 a i × 2 i , B = ∑ i = 0 2 b i × 2 i A = \sum\limits_{i=0}^{2}{a_i\times 2^i}, B = \sum\limits_{i=0}^{2}{b_i \times 2^i} A=i=02ai×2i,B=i=02bi×2i,易知 A , B ∈ N A,B \in \N A,BN

原式可化为 A + ( − 8 ) + B = A + B − 8 A+(-8)+B = A+B-8 A+(8)+B=A+B8

0 < A + B − 8 ≤ 7 ⇒ 8 < A + B ≤ 15 0 < A+B-8 \le 7 \Rightarrow 8 < A+B \le 15 0<A+B878<A+B15

值的位运算的结果不溢出即 − 8 ≤ A + B ≤ 7 -8 \le A+B \le 7 8A+B7

{ x ∣ − 8 ≤ x ≤ 7 } ∩ { x ∣ 8 < x ≤ 15 } = ∅ \{x|-8 \le x \le 7\}\cap\{x|8 < x \le 15\} = \varnothing {x8x7}{x8<x15}=

故该情况 不 存 在 \color{red}{不存在}

b.正数绝对值等于负数绝对值

数学运算结果: 0 0 0 ,符号为

位运算结果:值的位运算结果不溢出,符号位 0 + 1 = 1 0+1=1 0+1=1 ,变成了

设这里两个数补码分别为 [ 0 a 2 a 1 a 0 ] , [ 1 b 2 b 1 b 0 ] [0a_2a_1a_0], [1b_2b_1b_0] [0a2a1a0],[1b2b1b0]

A = ∑ i = 0 2 a i × 2 i , B = ∑ i = 0 2 b i × 2 i A = \sum\limits_{i=0}^{2}{a_i\times 2^i}, B = \sum\limits_{i=0}^{2}{b_i \times 2^i} A=i=02ai×2i,B=i=02bi×2i,易知 A , B ∈ N A,B \in \N A,BN

原式可化为 A + ( − 8 ) + B = A + B − 8 = 0 ⇒ A + B = 8 A+(-8)+B = A+B-8 = 0 \Rightarrow A+B=8 A+(8)+B=A+B8=0A+B=8

值的位运算的结果不溢出即 − 8 ≤ A + B ≤ 7 -8 \le A+B \le 7 8A+B7

{ x ∣ − 8 ≤ x ≤ 7 } ∩ { x ∣ x = 8 } = ∅ \{x|-8 \le x \le 7\}\cap\{x|x=8\} = \varnothing {x8x7}{xx=8}=

故该情况 不 存 在 \color{red}{不存在}

c.正数绝对值小于负数绝对值

数学运算结果:一定为负数,符号为

位运算结果:值的位运算结果不溢出,符号为 0 + 1 = 1 0 + 1 = 1 0+1=1 ,仍为

设这里两个数补码分别为 [ 0 a 2 a 1 a 0 ] , [ 1 b 2 b 1 b 0 ] [0a_2a_1a_0], [1b_2b_1b_0] [0a2a1a0],[1b2b1b0]

A = ∑ i = 0 2 a i × 2 i , B = ∑ i = 0 2 b i × 2 i A = \sum\limits_{i=0}^{2}{a_i\times 2^i}, B = \sum\limits_{i=0}^{2}{b_i \times 2^i} A=i=02ai×2i,B=i=02bi×2i,易知 A , B ∈ N A,B \in \N A,BN

原式可化为 A + ( − 8 ) + B = A + B − 8 A+(-8)+B = A+B-8 A+(8)+B=A+B8

− 8 ≤ A + B − 8 < 0 ⇒ 0 ≤ A + B < 8 -8 \le A+B-8 < 0 \Rightarrow 0 \le A+B < 8 8A+B8<00A+B<8

值的位运算结果不溢出即 − 8 ≤ A + B ≤ 7 -8 \le A+B \le 7 8A+B7

{ x ∣ 0 ≤ x < 8 } ⫋ { x ∣ − 8 ≤ x ≤ 7 } \{x|0 \le x < 8\}\subsetneqq\{x|-8 \le x \le 7\} {x0x<8}{x8x7}

故该情况 正 确 \color{red}{正确}

2) 值的位运算结果溢出时

1.正数+正数

数学运算结果:一定为正数,符号为

位运算结果:值的位运算结果溢出,符号位 0 + 0 + 1 = 1 0+0+1=1 0+0+1=1 ,变成了

设这里两个数补码分别为 [ 0 a 2 a 1 a 0 ] , [ 0 b 2 b 1 b 0 ] [0a_2a_1a_0], [0b_2b_1b_0] [0a2a1a0],[0b2b1b0]

A = ∑ i = 0 2 a i × 2 i , B = ∑ i = 0 2 b i × 2 i A = \sum\limits_{i=0}^{2}{a_i\times 2^i}, B = \sum\limits_{i=0}^{2}{b_i \times 2^i} A=i=02ai×2i,B=i=02bi×2i,易知 A , B ∈ N A,B \in \N A,BN

原式可化为 A + B A+B A+B

0 < A + B ≤ 7 0 < A+B \le 7 0<A+B7

值的位运算结果溢出即 A + B > 7 A+B>7 A+B>7

{ x ∣ 0 < x ≤ 7 } ∩ { x ∣ x > 7 } = ∅ \{x|0 < x \le 7\}\cap\{x|x>7\} = \varnothing {x0<x7}{xx>7}=

故该情况 不 存 在 \color{red}{不存在}

2.负数+负数

数学运算结果:一定为负数,符号为

位运算结果:值的位运算结果溢出,符号位 1 + 1 + 1 = 1 1+1+1=1 1+1+1=1 ,仍为

设这里两个数补码分别为 [ 1 a 2 a 1 a 0 ] , [ 1 b 2 b 1 b 0 ] [1a_2a_1a_0], [1b_2b_1b_0] [1a2a1a0],[1b2b1b0]

A = ∑ i = 0 2 a i × 2 i , B = ∑ i = 0 2 b i × 2 i A = \sum\limits_{i=0}^{2}{a_i\times 2^i}, B = \sum\limits_{i=0}^{2}{b_i \times 2^i} A=i=02ai×2i,B=i=02bi×2i,易知 A , B ∈ N A,B \in \N A,BN

原式可化为 − 8 + A + ( − 8 ) + B = A + B − 16 -8+A+(-8)+B = A+B-16 8+A+(8)+B=A+B16

− 8 ≤ A + B − 16 < 0 ⇒ 8 ≤ A + B < 16 -8 \le A+B -16< 0 \Rightarrow 8 \le A+B < 16 8A+B16<08A+B<16

值的位运算结果溢出即 A + B > 7 A+B>7 A+B>7

{ x ∣ 8 ≤ x < 16 } ⫋ { x ∣ x > 7 } \{x|8\le x < 16\}\subsetneqq\{x|x>7\} {x8x<16}{xx>7}

故该情况 正 确 \color{red}{正确}

3.一正一负
a.正数绝对值大于负数绝对值

数学运算结果:一定为正数,符号为

位运算结果:值的位运算结果溢出,符号位 0 + 1 + 1 = 0 0+1+1=0 0+1+1=0 ,仍为

设这里两个数补码分别为 [ 0 a 2 a 1 a 0 ] , [ 1 b 2 b 1 b 0 ] [0a_2a_1a_0], [1b_2b_1b_0] [0a2a1a0],[1b2b1b0]

A = ∑ i = 0 2 a i × 2 i , B = ∑ i = 0 2 b i × 2 i A = \sum\limits_{i=0}^{2}{a_i\times 2^i}, B = \sum\limits_{i=0}^{2}{b_i \times 2^i} A=i=02ai×2i,B=i=02bi×2i,易知 A , B ∈ N A,B \in \N A,BN

原式可化为 A + ( − 8 ) + B = A + B − 8 A+(-8)+B = A+B-8 A+(8)+B=A+B8

0 < A + B − 8 ≤ 7 ⇒ 8 < A + B ≤ 15 0<A+B-8\le 7 \Rightarrow 8<A+B\le15 0<A+B878<A+B15

值的位运算结果溢出即 A + B > 7 A+B>7 A+B>7

{ x ∣ 8 < x ≤ 15 } ⫋ { x ∣ x > 7 } \{x|8< x \le 15\}\subsetneqq\{x|x>7\} {x8<x15}{xx>7}

故该情况 正 确 \color{red}{正确}

b.正数绝对值等于负数绝对值

数学运算结果: 0 0 0 ,符号为

位运算结果:值的位运算结果溢出,符号位 0 + 1 + 1 = 0 0+1+1=0 0+1+1=0 ,仍为

设这里两个数补码分别为 [ 0 a 2 a 1 a 0 ] , [ 1 b 2 b 1 b 0 ] [0a_2a_1a_0], [1b_2b_1b_0] [0a2a1a0],[1b2b1b0]

A = ∑ i = 0 2 a i × 2 i , B = ∑ i = 0 2 b i × 2 i A = \sum\limits_{i=0}^{2}{a_i\times 2^i}, B = \sum\limits_{i=0}^{2}{b_i \times 2^i} A=i=02ai×2i,B=i=02bi×2i,易知 A , B ∈ N A,B \in \N A,BN

原式可化为 A + ( − 8 ) + B = A + B − 8 = 0 ⇒ A + B = 8 A+(-8)+B = A+B-8 = 0 \Rightarrow A+B=8 A+(8)+B=A+B8=0A+B=8

值的位运算结果溢出即 A + B > 7 A+B>7 A+B>7

{ x ∣ x = 8 } ⫋ { x ∣ x > 7 } \{x|x=8\}\subsetneqq\{x|x>7\} {xx=8}{xx>7}

故该情况 正 确 \color{red}{正确}

c.正数绝对值小于负数绝对值

数学运算结果:一定为负数 ,符号为

位运算结果:值的位运算结果溢出,符号位 0 + 1 + 1 = 0 0+1+1=0 0+1+1=0 ,变成了

设这里两个数补码分别为 [ 0 a 2 a 1 a 0 ] , [ 1 b 2 b 1 b 0 ] [0a_2a_1a_0], [1b_2b_1b_0] [0a2a1a0],[1b2b1b0]

A = ∑ i = 0 2 a i × 2 i , B = ∑ i = 0 2 b i × 2 i A = \sum\limits_{i=0}^{2}{a_i\times 2^i}, B = \sum\limits_{i=0}^{2}{b_i \times 2^i} A=i=02ai×2i,B=i=02bi×2i,易知 A , B ∈ N A,B \in \N A,BN

原式可化为 A + ( − 8 ) + B = A + B − 8 A+(-8)+B = A+B-8 A+(8)+B=A+B8

− 8 ≤ A + B − 8 < 0 ⇒ 0 ≤ A + B < 8 -8\le A+B - 8<0 \Rightarrow 0 \le A+B <8 8A+B8<00A+B<8

值的位运算结果溢出即 A + B > 7 A+B>7 A+B>7

{ x ∣ 0 < x < 8 } ∩ { x ∣ x > 7 } = ∅ \{x|0 < x < 8\}\cap\{x|x>7\} = \varnothing {x0<x<8}{xx>7}=

故该情况 不 存 在 \color{red}{不存在}

综上所述,所有存在的情况中,符号都是正确的,因此补码的正确性是可以保证的


总结

本文简单解释了补码的原理

并证明了补码的正确性


参考文献

[1] 《补码正确性的证明》

[2] 《补码(为什么按位取反再加一):告诉你一个其实很简单的问题》

转载请说明出处

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值