Loading docs/math/bit.md +156 −157 Original line number Diff line number Diff line 位运算就是把整数转换为二进制后,每位进行相应的运算得到结果。 常用的运算符共 6 种, 分别为与(`&`)、或(`|`)、异或(`^`)、取反(`~`)、左移(`<<`) 和右移(`>>`)。 常用的运算符共 6 种,分别为与(`&`)、或(`|`)、异或(`^`)、取反(`~`)、左移(`<<`) 和右移(`>>`)。 ## 与、或、异或 Loading @@ -11,43 +9,44 @@ 表示把两个整数分别转换为二进制后各位逐一比较。 <table><tr> <td style="text-align:center;">`&`</td><td>只有在两个(对应位数中)都为 1 时才为 1。</td> <td style="text-align:center;"><code>&</code></td><td>只有在两个(对应位数中)都为 1 时才为 1。</td> </tr><tr> <td style="text-align:center;">`|`</td><td>只要在两个(对应位数中)有一个 1 时就为 1。</td> <td style="text-align:center;"><code>|</code></td><td>只要在两个(对应位数中)有一个 1 时就为 1。</td> </tr><tr> <td style="text-align:center;">`^`</td><td>只有两个(对应位数)不同时才为 1。</td> <td style="text-align:center;"><code>^</code></td><td>只有两个(对应位数)不同时才为 1。</td> </tr></table> * `^` 运算的逆运算是它本身,也就是说两次异或同一个数最后结果不变,即 `(a ^ b) ^ b = a`。 > 举例: `^` 运算的逆运算是它本身,也就是说两次异或同一个数最后结果不变,即 `(a ^ b) ^ b = a`。 $$ \begin{aligned} &5&=&&(101)_2\\ &6&=&&(110)_2\\ &5\tt\,\&\,6\rm&=&&(100)_2&=\ 4\\ &5\tt\,|\,\rm6&=&&(111)_2&=\ 7\\ &5\tt\,\text{^}\,\rm6&=&&(011)_2&=\ 3\\ \end{aligned} $$ > 举例: > > $$ > \begin{aligned} > &5&=&&(101)_2\\ > &6&=&&(110)_2\\ > &5\tt\,\&\,6\rm&=&&(100)_2&=\ 4\\ > &5\tt\,|\,\rm6&=&&(111)_2&=\ 7\\ > &5\tt\,\text{^}\,\rm6&=&&(011)_2&=\ 3\\ > \end{aligned} > $$ #### 取反 取反是对 1 个数 num 进行的计算。 取反是对 1 个数 $num$ 进行的计算。 `~` 把 num 的补码中的 0 和 1 全部取反( 0 变为 1,1 变为 0)。 `~` 把 $num$ 的补码中的 0 和 1 全部取反 (0 变为 1,1 变为 0)。 - 补码——正数的补码为其(二进制)本身,负数的补码是其(二进制)取反后加一。 补码——正数的补码为其(二进制)本身,负数的补码是其(二进制)取反后 $+1$。 > 举例: $$ \begin{aligned} 5=(0000\ 0101)_2\\ 5\ 的补码=(1111\ 1010)_2\\ \tt\ \text{~}\rm5=(1111\ 1010)_2 \end{aligned} $$ > > $$ > \begin{aligned} > 5=(0000\ 0101)_2\\ > 5\ \text{的补码} =(1111\ 1010)_2\\ > \tt\ \text{~}\rm5=(1111\ 1010)_2 > \end{aligned} > $$ ## 左移和右移 Loading @@ -55,36 +54,36 @@ $$ 左移(`<<`) 将转化为二进制后的数字整体向左移动。 > `num<<i` // 表示将 num 转换为二进制后向左移动 i 位(所得的值) > `num << i` // 表示将 $num$ 转换为二进制后向左移动 $i$ 位(所得的值) 右移(`>>`) 将转化为二进制后的数字整体向右移动。 > `num>>i` // 表示将 num 转换为二进制后向左移动 i 位(所得的值) > `num >> i` // 表示将 $num$ 转换为二进制后向左移动 $i$ 位(所得的值) > > 举例: > > $$ > \begin{aligned} > &5&&=&&(101)_2\\ > &5\tt\,<<\,\rm2&&=&&(10100)_2\!\!\!&=&&\!\!\!20\\ > &5\tt>>\rm1&&=&&(10)_2&=&&2 > \end{aligned} > $$ $$ \begin{aligned} &5&&=&&(101)_2\\ &5\tt\,<<\,\rm2&&=&&(10100)_2\!\!\!&=&&\!\!\!20\\ &5\tt>>\rm1&&=&&(10)_2&=&&2 \end{aligned} $$ - 如上图,右移操作中末尾多余的 “1” 将会被舍弃。 如上图,右移操作中末尾多余的 “1” 将会被舍弃。 - 注意,左移和右移是有返回值的,并非对 num 本身进行操作。 注意,左移和右移是有返回值的,并非对 $num$ 本身进行操作。 * * * ## 位运算的应用 > num<<i 相当于 num 乘以 2 的 i 次方,而 num>>i 相当于 num/2 的 i 次方。 (位运算比 "%" 和 "/" 操作快得多) > (据 2018JSOI 夏令营课件,效率可以提高 60%) > `num << i` 相当于 $num$ 乘以 2 的 $i$ 次方,而 `num >> i` 相当于 $num$ 整除 2 的 $i$ 次方。 (位运算比 `%` 和 `/` 操作快得多) > (据 2018JSOI 夏令营,效率可以提高 60%) > > num\*10=(num<<1)+(num<<3) > `num * 10 = (num<<1) + (num<<3)` > > `num&1`相当于取 num 二进制的最末位,可用于判断 num 的奇偶性,二进制的最末位为 0 表示该数为偶数,最末位为 1 表示该数为奇数。 > `num & 1` 相当于取 $num$ 二进制的最末位,可用于判断 $num$ 的奇偶性,二进制的最末位为 0 表示该数为偶数,最末位为 1 表示该数为奇数。 > > ```cpp > //利用位运算的快捷的 swap 代码 Loading @@ -99,7 +98,7 @@ $$ ## 位运算的常用方法 - 乘以 2 运算 - 乘以 2 运算。 ```cpp int mulTwo(int n) { // 计算n*2 Loading @@ -107,7 +106,7 @@ int mulTwo(int n){//计算n*2 } ``` - 除以 2 运算 - 除以 2 运算。 ```cpp int divTwo(int n) { // 负奇数的运算不可用 Loading @@ -115,7 +114,7 @@ int divTwo(int n){//负奇数的运算不可用 } ``` - 乘以 2 的 $m$ 次方 - 乘以 2 的 $m$ 次方。 ```cpp int mulTwoPower(int n, int m) { // 计算n*(2^m) Loading @@ -123,7 +122,7 @@ int mulTwoPower(int n,int m){//计算n*(2^m) } ``` - 除以 2 的 $m$ 次方 - 除以 2 的 $m$ 次方。 ```cpp int divTwoPower(int n, int m) { // 计算n/(2^m) Loading @@ -131,7 +130,7 @@ int divTwoPower(int n,int m){//计算n/(2^m) } ``` - 判断一个数的奇偶性 - 判断一个数的奇偶性。 ```cpp boolean isOddNumber(int n) { Loading @@ -139,7 +138,7 @@ boolean isOddNumber(int n){ } ``` - 取绝对值(某些机器上,效率比 `n>0 ? n:-n` 高) - 取绝对值(某些机器上,效率比 `n > 0 ? n : -n` 高)。 ```cpp int abs(int n) { Loading @@ -150,7 +149,7 @@ return (n ^ (n >> 31)) - (n >> 31); } ``` - 取两个数的最大值(某些机器上,效率比 `a>b ? a:b` 高) - 取两个数的最大值(某些机器上,效率比 `a > b ? a : b` 高)。 ```cpp int max(int a, int b) { Loading @@ -159,7 +158,7 @@ int max(int a,int b){ } ``` - 取两个数的最小值(某些机器上,效率比 `a>b ? b:a` 高) - 取两个数的最小值(某些机器上,效率比 `a > b ? b : a` 高)。 ```cpp int min(int a, int b) { Loading @@ -168,15 +167,15 @@ int min(int a,int b){ } ``` - 判断符号是否相同 - 判断符号是否相同。 ```cpp boolean isSameSign(int x, int y) { // 有0的情况例外 return (x ^ y) >= 0; // true 表示 x和y有相同的符号, false表示x,y有相反的符号。 return (x ^ y) >= 0; // true 表示x和y有相同的符号,false 表示x,y有相反的符号。 } ``` - 计算 2 的 $n$ 次方 - 计算 2 的 $n$ 次方。 ```cpp int getFactorialofTwo(int n) { // n > 0 Loading @@ -184,7 +183,7 @@ int getFactorialofTwo(int n){//n > 0 } ``` - 判断一个数是不是 2 的幂 - 判断一个数是不是 2 的幂。 ```cpp boolean isFactorialofTwo(int n) { Loading @@ -194,7 +193,7 @@ boolean isFactorialofTwo(int n){ } ``` - 对 2 的 $n$ 次方取余 - 对 2 的 $n$ 次方取余。 ```cpp int quyu(int m, int n) { //n为2的次方 Loading @@ -204,7 +203,7 @@ int quyu(int m,int n){//n为2的次方 } ``` - 求两个整数的平均值 - 求两个整数的平均值。 ```cpp int getAverage(int x, int y) { Loading @@ -214,4 +213,4 @@ int getAverage(int x, int y){ #### 题目推荐 [CODE\[VS\] 2743 黑白棋游戏 ](http://codevs.cn/problem/2743/) [CODEVS 2743 黑白棋游戏](http://codevs.cn/problem/2743/) Loading
docs/math/bit.md +156 −157 Original line number Diff line number Diff line 位运算就是把整数转换为二进制后,每位进行相应的运算得到结果。 常用的运算符共 6 种, 分别为与(`&`)、或(`|`)、异或(`^`)、取反(`~`)、左移(`<<`) 和右移(`>>`)。 常用的运算符共 6 种,分别为与(`&`)、或(`|`)、异或(`^`)、取反(`~`)、左移(`<<`) 和右移(`>>`)。 ## 与、或、异或 Loading @@ -11,43 +9,44 @@ 表示把两个整数分别转换为二进制后各位逐一比较。 <table><tr> <td style="text-align:center;">`&`</td><td>只有在两个(对应位数中)都为 1 时才为 1。</td> <td style="text-align:center;"><code>&</code></td><td>只有在两个(对应位数中)都为 1 时才为 1。</td> </tr><tr> <td style="text-align:center;">`|`</td><td>只要在两个(对应位数中)有一个 1 时就为 1。</td> <td style="text-align:center;"><code>|</code></td><td>只要在两个(对应位数中)有一个 1 时就为 1。</td> </tr><tr> <td style="text-align:center;">`^`</td><td>只有两个(对应位数)不同时才为 1。</td> <td style="text-align:center;"><code>^</code></td><td>只有两个(对应位数)不同时才为 1。</td> </tr></table> * `^` 运算的逆运算是它本身,也就是说两次异或同一个数最后结果不变,即 `(a ^ b) ^ b = a`。 > 举例: `^` 运算的逆运算是它本身,也就是说两次异或同一个数最后结果不变,即 `(a ^ b) ^ b = a`。 $$ \begin{aligned} &5&=&&(101)_2\\ &6&=&&(110)_2\\ &5\tt\,\&\,6\rm&=&&(100)_2&=\ 4\\ &5\tt\,|\,\rm6&=&&(111)_2&=\ 7\\ &5\tt\,\text{^}\,\rm6&=&&(011)_2&=\ 3\\ \end{aligned} $$ > 举例: > > $$ > \begin{aligned} > &5&=&&(101)_2\\ > &6&=&&(110)_2\\ > &5\tt\,\&\,6\rm&=&&(100)_2&=\ 4\\ > &5\tt\,|\,\rm6&=&&(111)_2&=\ 7\\ > &5\tt\,\text{^}\,\rm6&=&&(011)_2&=\ 3\\ > \end{aligned} > $$ #### 取反 取反是对 1 个数 num 进行的计算。 取反是对 1 个数 $num$ 进行的计算。 `~` 把 num 的补码中的 0 和 1 全部取反( 0 变为 1,1 变为 0)。 `~` 把 $num$ 的补码中的 0 和 1 全部取反 (0 变为 1,1 变为 0)。 - 补码——正数的补码为其(二进制)本身,负数的补码是其(二进制)取反后加一。 补码——正数的补码为其(二进制)本身,负数的补码是其(二进制)取反后 $+1$。 > 举例: $$ \begin{aligned} 5=(0000\ 0101)_2\\ 5\ 的补码=(1111\ 1010)_2\\ \tt\ \text{~}\rm5=(1111\ 1010)_2 \end{aligned} $$ > > $$ > \begin{aligned} > 5=(0000\ 0101)_2\\ > 5\ \text{的补码} =(1111\ 1010)_2\\ > \tt\ \text{~}\rm5=(1111\ 1010)_2 > \end{aligned} > $$ ## 左移和右移 Loading @@ -55,36 +54,36 @@ $$ 左移(`<<`) 将转化为二进制后的数字整体向左移动。 > `num<<i` // 表示将 num 转换为二进制后向左移动 i 位(所得的值) > `num << i` // 表示将 $num$ 转换为二进制后向左移动 $i$ 位(所得的值) 右移(`>>`) 将转化为二进制后的数字整体向右移动。 > `num>>i` // 表示将 num 转换为二进制后向左移动 i 位(所得的值) > `num >> i` // 表示将 $num$ 转换为二进制后向左移动 $i$ 位(所得的值) > > 举例: > > $$ > \begin{aligned} > &5&&=&&(101)_2\\ > &5\tt\,<<\,\rm2&&=&&(10100)_2\!\!\!&=&&\!\!\!20\\ > &5\tt>>\rm1&&=&&(10)_2&=&&2 > \end{aligned} > $$ $$ \begin{aligned} &5&&=&&(101)_2\\ &5\tt\,<<\,\rm2&&=&&(10100)_2\!\!\!&=&&\!\!\!20\\ &5\tt>>\rm1&&=&&(10)_2&=&&2 \end{aligned} $$ - 如上图,右移操作中末尾多余的 “1” 将会被舍弃。 如上图,右移操作中末尾多余的 “1” 将会被舍弃。 - 注意,左移和右移是有返回值的,并非对 num 本身进行操作。 注意,左移和右移是有返回值的,并非对 $num$ 本身进行操作。 * * * ## 位运算的应用 > num<<i 相当于 num 乘以 2 的 i 次方,而 num>>i 相当于 num/2 的 i 次方。 (位运算比 "%" 和 "/" 操作快得多) > (据 2018JSOI 夏令营课件,效率可以提高 60%) > `num << i` 相当于 $num$ 乘以 2 的 $i$ 次方,而 `num >> i` 相当于 $num$ 整除 2 的 $i$ 次方。 (位运算比 `%` 和 `/` 操作快得多) > (据 2018JSOI 夏令营,效率可以提高 60%) > > num\*10=(num<<1)+(num<<3) > `num * 10 = (num<<1) + (num<<3)` > > `num&1`相当于取 num 二进制的最末位,可用于判断 num 的奇偶性,二进制的最末位为 0 表示该数为偶数,最末位为 1 表示该数为奇数。 > `num & 1` 相当于取 $num$ 二进制的最末位,可用于判断 $num$ 的奇偶性,二进制的最末位为 0 表示该数为偶数,最末位为 1 表示该数为奇数。 > > ```cpp > //利用位运算的快捷的 swap 代码 Loading @@ -99,7 +98,7 @@ $$ ## 位运算的常用方法 - 乘以 2 运算 - 乘以 2 运算。 ```cpp int mulTwo(int n) { // 计算n*2 Loading @@ -107,7 +106,7 @@ int mulTwo(int n){//计算n*2 } ``` - 除以 2 运算 - 除以 2 运算。 ```cpp int divTwo(int n) { // 负奇数的运算不可用 Loading @@ -115,7 +114,7 @@ int divTwo(int n){//负奇数的运算不可用 } ``` - 乘以 2 的 $m$ 次方 - 乘以 2 的 $m$ 次方。 ```cpp int mulTwoPower(int n, int m) { // 计算n*(2^m) Loading @@ -123,7 +122,7 @@ int mulTwoPower(int n,int m){//计算n*(2^m) } ``` - 除以 2 的 $m$ 次方 - 除以 2 的 $m$ 次方。 ```cpp int divTwoPower(int n, int m) { // 计算n/(2^m) Loading @@ -131,7 +130,7 @@ int divTwoPower(int n,int m){//计算n/(2^m) } ``` - 判断一个数的奇偶性 - 判断一个数的奇偶性。 ```cpp boolean isOddNumber(int n) { Loading @@ -139,7 +138,7 @@ boolean isOddNumber(int n){ } ``` - 取绝对值(某些机器上,效率比 `n>0 ? n:-n` 高) - 取绝对值(某些机器上,效率比 `n > 0 ? n : -n` 高)。 ```cpp int abs(int n) { Loading @@ -150,7 +149,7 @@ return (n ^ (n >> 31)) - (n >> 31); } ``` - 取两个数的最大值(某些机器上,效率比 `a>b ? a:b` 高) - 取两个数的最大值(某些机器上,效率比 `a > b ? a : b` 高)。 ```cpp int max(int a, int b) { Loading @@ -159,7 +158,7 @@ int max(int a,int b){ } ``` - 取两个数的最小值(某些机器上,效率比 `a>b ? b:a` 高) - 取两个数的最小值(某些机器上,效率比 `a > b ? b : a` 高)。 ```cpp int min(int a, int b) { Loading @@ -168,15 +167,15 @@ int min(int a,int b){ } ``` - 判断符号是否相同 - 判断符号是否相同。 ```cpp boolean isSameSign(int x, int y) { // 有0的情况例外 return (x ^ y) >= 0; // true 表示 x和y有相同的符号, false表示x,y有相反的符号。 return (x ^ y) >= 0; // true 表示x和y有相同的符号,false 表示x,y有相反的符号。 } ``` - 计算 2 的 $n$ 次方 - 计算 2 的 $n$ 次方。 ```cpp int getFactorialofTwo(int n) { // n > 0 Loading @@ -184,7 +183,7 @@ int getFactorialofTwo(int n){//n > 0 } ``` - 判断一个数是不是 2 的幂 - 判断一个数是不是 2 的幂。 ```cpp boolean isFactorialofTwo(int n) { Loading @@ -194,7 +193,7 @@ boolean isFactorialofTwo(int n){ } ``` - 对 2 的 $n$ 次方取余 - 对 2 的 $n$ 次方取余。 ```cpp int quyu(int m, int n) { //n为2的次方 Loading @@ -204,7 +203,7 @@ int quyu(int m,int n){//n为2的次方 } ``` - 求两个整数的平均值 - 求两个整数的平均值。 ```cpp int getAverage(int x, int y) { Loading @@ -214,4 +213,4 @@ int getAverage(int x, int y){ #### 题目推荐 [CODE\[VS\] 2743 黑白棋游戏 ](http://codevs.cn/problem/2743/) [CODEVS 2743 黑白棋游戏](http://codevs.cn/problem/2743/)