数字电路【原码,补码和反码】

晶体管容易实现加法电路,但实现减法电路很复杂,

二进制码型的乘法由被乘数和0的左移和加法构成,

除法由被除数或余数减去被除数的右移构成,

因此如果可以将减法用加法代替,则所有二进制计算都可以用加法和位移运算代替

首先采用原码

原码是指用二进制数的最高位表示正负,其余位表示数值大小

例如 7 = 0111B -7 = 1111B

但是原码存在的问题是做减法时需要先比较二者的绝对值大小,用绝对值较大的一个的符号位作为差值符号位,然后做绝对值相减

很显然,原码的减法计算实际上没有完成用加法替代减法的功能,并且需要比较电路,实现会很复杂,并且原码存在“负0” 如 1000B是负0,而0000B是正0

为了将加法替换位减法可以使用模运算,

时钟是一个模12的系统,设当前时间为 9:00 如果想要将指针拨到 5:00,有两种方式

第一种是逆时针拨动4个小时,另一种是顺时针拨动8个小时

由此可见在模12的运算中 9 + 8 mod(12) 和 9 - 4 mod(12)同余

因此在时钟系统里减4的运算可以用加8来代替

并且容易发现,在模m的系统里找一个x的补数,可以通过m - x来得到,其中x为小于m的正整数

这同样可以用于二进制的系统

以4bit的二进制为例,很显然一共有16个数,0 ~ 15

9 - 4 mod(16) = 5 9 + 12 mod(16) = 5

1001 - 0100 = 0101 1001 + 1100 = 1 0101

对1 0101取模,即减去16,即可得到0101,

在n bit补数取模的系统中,N > 0时 N补 = N,N < 0时,N补 = 2 ^ n + N,

这样在计算4 bit 9 - 4时只需要替换成9 + 12 即可,但是问题在于求-4的补码使用公式2 ^ 4 + (-4) = 16 - 4,这一步仍然需要计算减法,

于是引入反码,观察2^n - 1可以发现这是一个n bit全1的数并且它和任意一个n bit数x做差得到的结果都是对x按位取反得到的而取反是很容易实现的,

对于反码 N > 0时 N反 = N,N < 0 时,N反 = 2 ^ n - 1 + N,或者对N按位取反,

但是由于反码的模是2 ^ n - 1,就导致存在两个问题:

第一是存在负0,以4 bit为例1111就是负0,同时1111 也是 2 ^ 4 - 1 = 15,

第二个问题是反码运算需要将溢出数回加到结果,

以十进制计算3 - 1 = 2为例,在4 bit二进制数中,3(D) = 0011(B),-1(D) = 1110(B)

于是上述减法可以转换为加法,0011 + 1110 = 1 0001,如果我们舍去溢出的1则结果为 0001(B)= 1(D),很显然不正确,这就需要将最高符号位回加得到0010(B) = 2 (D),

可以假设n bit数A和B相加有A + B = S,并且假设S出现第n + 1位的进位,那么S = R + C * 2 ^ n,其中R是低n bit的结果,C是第n + 1位的二进制数,这里只考虑C = 1,

由于反码相当于在模2 ^ n - 1中计算,那么R + C * 2 ^ n mod(2 ^ n - 1) ≡ R + C * 1,由于C = 1,所以真正的结果S实际上应该要在低位R的结果上加1才能得到。

尽管反码存在这些问题,但结合反码和补码的公式可以发现,当N < 0时,N反 = 2 ^ n - 1 + N,而N补 = 2 ^ n + N,于是可以得到N补 = N反 + 1,

这样我们就可以绕回到补码上,当要计算减法 X - N 时只需要先对N按位取反(等价于 2 ^ n - 1 + (-N))得到N反,然后加1即可得到N补,这样X - N就转为了X + N补,

并且整个过程都绕开了减法。

接着考虑补码的码型,我们规定用最高bit是否为1来代表数字是负数或正数,在一个n bit的二进制数中,第n位为1的数1000···000的值必然等于2 ^ (n-1),

结合补码公式,N < 0时,2 ^ n + N的二进制数就必须大于等于2 ^ (n-1),

有 2 ^ n + N >= 2 ^ (n-1),那么 N >= 2 ^ (n-1) - 2 * 2 ^ (n-1),于是 N >= - 2 ^ (n-1)我们得到了n bit补码的下界,

接着就容易得到当N > 0时,N的最高bit不能为1,那么N < 2 ^ (n-1),

可见正数部分从1到2 ^ (n-1) - 1一共有2 ^ (n-1) - 1个元素,负数部分从-1到-2 ^ (n-1),一共有2 ^ (n-1)个元素,两者相加刚好差一个0,这样就不存在负0,

并且由于模是 2 ^ n,当出现n + 1进位时R + C * 2 ^ n mod(2 ^ n) ≡ R + C * 0,这说明n + 1的溢出直接丢弃就好。

另外在补码中有一个特殊的成员,就是2 ^ (n - 1),这个数的补码就是自身并且只在负数中存在。

我们已经知道,在一个n bit的系统中,A和B如果互为补数,那么必然有A + B = 2 ^ n,

调换一下位置可以得到-B = A - 2 ^ n,由于A,B都是正数,A可以用 bn-1 * 2 ^ (n-1) + ∑bi * 2 ^ i来表示,

于是,A - 2 ^ n = -bn-1 * 2 ^ (n-1) + ∑bi * 2 ^ i(0<=i<=n-2),如果A的第n-1位为1,那么它对应的实际十进制数的负数就等于-bn-1 * 2 ^ (n-1) + ∑bi * 2 ^ i,其中bn-1 = 1,

如果A的第n - 1位为0,则A可以表示为 A = bn-1 * 2^(n-1) ∑bi * 2 ^ i(0<=i<=n-2),

所以可以总结出补码的计算公式 N = -bn-1 * 2 ^ (n-1) + ∑bi * 2 ^ i(0<=i<=n-2),这样就把正数和负数的补码与十进制数进行了统一。

思考:为什么两个二进制数补码相加时,和的符号位等于两数的符号位和最高有效数位进位的相加结果?(舍弃符号位的进位)。

posted @ 2026-08-13 14:40  lf123z  阅读(1)  评论(0)    收藏  举报