Commit bf10076a authored by ir1d's avatar ir1d Committed by Xeonacid
Browse files

feat: update bit operations (#471)

* style: format markdown files with remark-lint

* Update bit.md

* style: format markdown files with remark-lint

* feat: minor update on bit.md
parent c39c4aa4
Loading
Loading
Loading
Loading
+48 −21
Original line number Diff line number Diff line
@@ -30,7 +30,7 @@
> \end{aligned}
> $$

#### 取反
## 取反

取反是对 1 个数 $num$ 进行的计算。

@@ -64,13 +64,13 @@
>
> $$
> \begin{aligned}
> &5&&=&&(101)_2\\
> &5\tt\,<<\,\rm2&&=&&(10100)_2\!\!\!&=&&\!\!\!20\\
> &5\tt>>\rm1&&=&&(10)_2&=&&2
> &5&&=&&(00000101)_2\\
> &5\tt\,<<\,\rm1&&=&&(00001010)_2\!\!\!&=&&\!\!\!20\\
> &5\tt>>\rm1&&=&&(00000010)_2&=&&2
> \end{aligned}
> $$

如上图,右移操作中末尾多余的 “1” 将会被舍弃。
在 C++ 中,右移操作中末尾多余的 “1” 将会被舍弃。而左侧较为复杂,对于无符号数,会在左侧补 0;而对于有符号数,则会用最高位的数补齐(Replicate most significant bit on left)。

注意,左移和右移是有返回值的,并非对 $num$ 本身进行操作。

@@ -78,21 +78,36 @@

## 位运算的应用

> `num << i` 相当于 $num$ 乘以 2 的 $i$ 次方,而 `num >> i` 相当于 $num$ 整除 2 的 $i$ 次方。 (位运算比 `%` 和 `/` 操作快得多)
> (据 2018JSOI 夏令营,效率可以提高 60%)
>
> `num * 10 = (num<<1) + (num<<3)`
>
> `num & 1` 相当于取 $num$ 二进制的最末位,可用于判断 $num$ 的奇偶性,二进制的最末位为 0 表示该数为偶数,最末位为 1 表示该数为奇数。
>
> ```cpp
> //利用位运算的快捷的 swap 代码
> void swap(int a, int b){
> 	a = a ^ b;   
> 	b = a ^ b;  
> 	a = a ^ b;
> }
> ```
如果 $num$ 是正数,`num << i` 相当于 $num$ 乘以 2 的 $i$ 次方,而 `num >> i` 相当于 $num$ 除以 2 的 $i$ 次方。 (位运算比 `%``/` 操作快得多)
(据 2018JSOI 夏令营,效率可以提高 60%)

!!! warning
    为什么要强调是正数呢?考虑一下 `-1 >> 3`

`num * 10 = (num<<1) + (num<<3)`

`num & 1` 相当于取 $num$ 二进制的最末位,可用于判断 $num$ 的奇偶性,二进制的最末位为 0 表示该数为偶数,最末位为 1 表示该数为奇数。

```cpp
//利用位运算的快捷的 swap 代码
void swap(int a, int b){
	a = a ^ b;   
	b = a ^ b;  
	a = a ^ b;
}
```

一个数的二进制表示可以看作是一个集合(0 表示不在集合中,1 表示在集合中)。比如集合 `{1, 3, 4, 8}`,可以表示成 `0b00000000000000000000000100011010`,十进制就是 $2^8+2^4+2^3+2^1=282$。

而对应的位运算也就可以看作是对集合进行的操作。

| 操作  |            集合表示 |  位运算语句  |
| --- | --------------: | :-----: |
| 交集  |      $a \cap b$ | `a & b` |
| 并集  |      $a \cup b$ | `a | b` |
| 补集  |       $\bar{a}$ |   `~a`  |
| 差集  | $a \setminus b$ |   `~a`  |
| 对称差 |  $a\triangle b$ | `a ^ b` |

* * *

@@ -211,6 +226,18 @@

    ```

#### 题目推荐
-   遍历一个集合的子集
    ```cpp
    int b = 0;
    do {
      // process subset b
    } while (b = (b - x) & x);
    ```

## 题目推荐

[CODEVS 2743 黑白棋游戏](http://codevs.cn/problem/2743/)

## 参考

位运算技巧:<https://graphics.stanford.edu/~seander/bithacks.html>