学习:回归本源——位运算及其应用

· · 个人记录

<center><h2>学习:回归本源——位运算及其应用</h2></center>
<center>中山一中 陈煜</center>

前言

  二进制是计算技术中广泛采用的一种数制。它的基数为2,进位规则是“逢二进一”,借位规则是“借一当二”。程序中的所有数在计算机内存中都是以二进制的形式储存的,位运算就是直接对整数在内存中的二进制位进行操作。
  因此,在电子计算机中,位运算可以说是比四则运算更加基础的运算,但是因为它不是数学的基本运算而不容易得到重视,本文将通过位运算及其应用的介绍,使更多 Oier 掌握相关的黑科技。

说明

1. 基本运算

1.1 与、或、非、异或

  与、或、非、异或四种基本运算对应的汇编指令及在 C++ 中的表示方法如下: 异或
and or not xor
\text& $\text $ \text ! \text ^

  由上可得:带符号整数和无符号整数并没有对应不同的汇编指令,即带符号整数的符号位进行位运算的规则和其他位相同。

  位运算,顾名思义是对二进制位的运算,不会涉及进位,进行位运算的效果如下: p q \text{p&q} $\text{p q}$ \text{p^q}
1 1 1 1 0
0 1 0 1 1
1 0 0 1 1
0 0 0 0 0
p !\ p
1 0
0 1
  简单的找个规律:与运算“有0为0”,或运算“有1为1”,非运算”取反“,异或运算“相同为0,不同为1”。然后我们发现,异或运算的规律比较鬼畜,其实异或运算是可以用其它三种运算表示出来的:$\text{a^b=(a b)&(!a !b)}$(方法不只一种,有兴趣的读者可以自行探究,十分有趣)。

1.2 移位运算

  移位运算分为逻辑移位、算术移位、循环移位、带进位移位四种。最后一种我们暂且不讨论(涉及过于高深的CF标志位)。
  注意:以下对于”\text{ x 左移或右移 y 位}“,默认 y 非负且小于 x 的位宽,即假如 x 为32为整数,y 只能在0到31之间取值。

逻辑移位:

算术移位:

循环移位:(顾名思义啦)

移位运算的数学含义:
  逻辑移位被用于处理无符号整数,算术移位被用于处理带符号整数。
  左移 y 位和 \times 2^y 等价,右移 y 位和 \div 2^y 等价(向下取整)。
  举个例子就好懂了:0101左移1位,变成1010,5变成10;感性理解为相邻的二进制位、高位代表的权值为低位的两倍。
   为什么有、无符号整数右移方式不同?(以八位有符号二进制举例)
  计算机一律使用补码进行运算,补码由符号位、数值位组成,补码规则如下:

  用补码进行运算,减法可以用加法实现,例:9-5 = 9+(-5) = 00001001 + 11111011 = 00000100 = 4,也就是说符号位可以直接参与运算了,这是原码、反码所没有的优点,为乘除法器算器铺平了道路,这是后话。
  我们发现,原码除去符号位就成了“绝对值”,而负整数的补码每一位经原码反转所得,假如我们用逻辑右移给高位补0的话,反转回原码反而绝对值变大了,与我们所期待的数学含义矛盾,因此我们给他补1从而使得移位运算在处理负数时数学含义不变。

C++ 中的移位运算:
  在 C++ 中,无符号整数的移位采用逻辑移位,带符号整数的移位采用算术移位,所以我们可以按照移位运算的数学含义进行使用。
  表示方法如下:

左移 右移
<< >>

  但是我们发现,对于带符号整数,我们不能进行逻辑右移了,但是不用慌,把它强行转换成无符号整数后(符号位就是最高位)就可以进行逻辑移位了,移完再转换成带符号整数(最高位变成符号位)即可。