二进制运算

二进制逻辑运算

逻辑加法(“或”运算)

逻辑加法通常用符号“+”或“∨”来表示。逻辑加法运算规则如下:

1
2
3
4
0+0=0, 0∨0=0
0+1=1, 0∨1=1
1+0=1, 1∨0=1
1+1=1, 1∨1=1

从上式可见,逻辑加法有“或”的意义。也就是说,在给定的逻辑变量中,A或B只要有一个为1,其逻辑加的结果就为1;只有当两者都为0时逻辑加的结果才为0。

逻辑乘法(“与”运算)

逻辑乘法通常用符号“×”或“∧”或“·”来表示。逻辑乘法运算规则如下:

1
2
3
4
0×0=0, 0∧0=0, 0·0=0
0×1=0, 0∧1=0, 0·1=0
1×0=0, 1∧0=0, 1·0=0
1×1=1, 1∧1=1, 1·1=1

不难看出,逻辑乘法有“与”的意义。它表示只当参与运算的逻辑变量都同时取值为1时,其逻辑乘积才等于1。

异或逻辑运算(“半加”运算)

异或运算通常用符号”⊕”表示,其运算规则为:

1
2
3
4
0⊕0=0 0同0异或,结果为0
0⊕1=1 0同1异或,结果为1
1⊕0=1 1同0异或,结果为1
1⊕1=0 1同1异或,结果为0

即两个逻辑变量相异,输出才为1

反码

将二进制数反转,得到的数即为原二进制的反码(ones’ complement)。若某一位为0,则使其变为1,反之亦然。

例如,+3是0011,用反码表示-3便是1100。

下表列出了4-bit二进数所能表示的整数。wiki 反码

二进数 无符号 符号比特 反码
0000 0 0 0
0001 1 1 1
0010 2 2 2
0011 3 3 3
0100 4 4 4
0101 5 5 5
0110 6 6 6
0111 7 7 7
1000 8 -0 -7
1001 9 -1 -6
1010 10 -2 -5
1011 11 -3 -4
1100 12 -4 -3
1101 13 -5 -2
1110 14 -6 -1
1111 15 -7 -0

补码

wiki 补码

补码(英语:2’s complement)是一种用二进制表示有号数的方法,也是一种将数字的正负号变号的方式,常在计算机科学中使用。

一个数字的补码就是将该数字作比特反相运算(即反码),再将结果加1。即:反码加1 。在补码系统中,一个负数就是用其对应
正数的补码来表示。

以下用4位的补码数字来说明补码系统的数字表示方式

  • 在表示正数和零时,补码数字和一般二进制一样,唯一的不同是在补码系统中,正数的最高比特恒为0,因此4位的补码正数,最大数字为0111 (7)。
  • 补码数字的负数,最高比特恒为1,4位补码的数字中,最接近0的负数为1111 (-1),以此类推,因此绝对值最大的负数是1000(-8)。

以上的表示方式在计算机处理时格外方便,用以下的例子说明:

1
2
3
4
    0011 ( 3)
+ 1111 (-1)
--------------
10010 ( 2)

结果10010似乎是错的,因为已经超过四个比特,不过若忽略掉(从右数起的)第5个比特,结果是0010 (2),和我们计算的结果一样。
而且若可以将二进制的1111 (-1)变号为0001 (1),以上的式子也可以计算减法:3-1 = 2。

运算

加法

二补数系统数字的加法和一般加法相同,而且在运算完成后就可以看出结果的正负号,不需特别的处理。

正数与负数相加不会出现上溢错误,因为它们的和一定会小于加数。只有在两个同正负号的数相加时,上溢错误才有可能发生,这时候它们的和与加数的正负号相反。

以15加 -5为例:

1
2
3
4
5
 11111 111(进位)
0000 1111 (15)
+ 1111 1011 (-5)
==================
0000 1010 (10)

由于加数和被加数都是8位,因此运算结果也限制在8位内。第8位相加后产生的进位不考虑(因为不存在第9比特)的1被忽略,所以其结果为10。而15 + (-5) = 10,计算结果正确。

在以上计算式中,可以由进位列的最左侧二个比特得知结果是否出现溢出。溢出就是数字的绝对值太大,以致于无法在指定的二进制比特个数来表示(在此例中,是超过8位的范围)。若进位列的最左侧二个比特同为0或同为1,表示结果正确,若是一个为0,另一个为1,表示出现溢出错误。也可以对此二个比特进行异或运算,结果为1时,表示出现溢出错误。以下以7 + 3的4位加法说明溢出错误的情形。

1
2
3
4
5
 0111 (进位)
0111 (7)
+ 0011 (3)
=============
1010 (−6)

结果不正确!
在此例中,进位列的最左侧二个比特为01,因此出现溢出错误。溢出的原因是7 + 3的结果(10)超过补码系统4位所可以表示的数字范围 -8~7。

故为防止溢出错误,二补数在进行加法运算时通常讲符号位进行复制后追加到最高位之前,即设二补数B的位数为WIDTH,则B′={B[WIDTH-1],B}。应注意此处B′的位数为WIDTH+1。 如上两例用此方法进行计算:

1
2
3
4
5
  11 1111 111(进位)
0 0000 1111 (15)
+1 1111 1011 (-5)
==================
(1)0 0000 1010 (10)

由于WIDTH+1=8+1=9,故而第十位的1同样由于溢出而被省略,结果仍为10。两负数(符号位为1)相加时同理。

1
2
3
4
5
   111 (进位)
0 0111 (7)
+0 0011 (3)
=============
0 1010 (10)

结果正确!
由于WIDTH+1=4+1=5,故第五位的0仍为符号位,得结果正数10(十进制)。

减法

减法通常转化为加法进行运算,将减数取补之后,再与被减数进行加法运算,即可得出差。

乘法

乘法在计算机的世界里其实就是不断的做加法。

例如:3*5=3+3+3+3+3=15

除法

除法就是相减。

例如:10/3=10-3-3-3=1mod3 而减法又可做二的补数相加,所以所有四则运算的基础都是由加法而来。

补码的工作原理

为什么补码能这么巧妙实现了正负数的加减运算?
答案是:指定n比特字长,那么就只有2n个可能的值,加减法运算都存在上溢出与下溢出的情况,实际上都等价于模2n的加减法运算。
这对于n比特无符号整数类型或是n比特有符号整数类型都同样适用。

例如,8位无符号整数的值的范围是0到255.因此4+254将上溢出,结果是2,即(4+254) \equiv 258 \equiv 2 \pmod{256}。

例如,8位有符号整数的值的范围,如果规定为−128到127,则126+125将上溢出,结果是−5,即(126+125) \equiv 251 \equiv -5 \pmod{256}。

对于8位字长的有符号整数类型,以28即256为模,则

1
2
3
4
5
-128 & \equiv 128 \pmod{256} \\
-127 & \equiv 129 \pmod{256} \\

-2 & \equiv 254 \pmod{256} \\
-1 & \equiv 255 \pmod{256} \\

所以模256下的加减法,用0, 1, 2,…, 254,255表示其值,或者用−128, −127,…, −1, 0, 1, 2,…,127是完全等价的。−128与128,−127与129,…,−2与254,−1与255可以互换而加减法的结果不变。从而,把8位(octet)的高半部分(即二进制的1000 0000到1111 1111)解释为−128到−1,同样也实现了模256的加减法,而且所需要的CPU加法运算器的电路实现与8位无符号整数并无不同。

实际上对于8比特的存储单元,把它的取值[00000000,…, 11111111]解释为[0, 255],或者[-1, 254],或者[-2, 253],或者[-128, 127],或者[-200, 55],甚至或者[500, 755],对于加法硬件实现并无不同。