mirror of https://github.com/OI-wiki/OI-wiki
feat(lang/optimizations): 添加有符号移位相关说明 (#4711)
* feat(lang/optimizations): 添加有符号移位相关说明 * style: format markdown files with remark-lint --------- Co-authored-by: 24OI-bot <15963390+24OI-bot@users.noreply.github.com>pull/4717/head
parent
df71386a5e
commit
c179934094
|
@ -48,7 +48,7 @@ int binary_search(int start, int end, int key) {
|
|||
```
|
||||
|
||||
???+note
|
||||
对于 $n$ 是有符号数的情况,当你可以保证 $n\ge 0$ 时,`n >> 1` 比 `n / 2` 指令数更少。
|
||||
参考 [编译优化 #位运算代替乘法](/lang/optimizations/#%E4%BD%8D%E8%BF%90%E7%AE%97%E4%BB%A3%E6%9B%BF%E4%B9%98%E6%B3%95),对于 $n$ 是有符号数的情况,当你可以保证 $n\ge 0$ 时,`n >> 1` 比 `n / 2` 指令数更少。
|
||||
|
||||
### 最大值最小化
|
||||
|
||||
|
|
|
@ -409,6 +409,32 @@ a = x * 2; // bad!
|
|||
a = x << 1; // good!
|
||||
```
|
||||
|
||||
需要注意的是有符号数和无符号数在移位 (shifting) 和类型提升 (promotion) 层面有明显的差异。符号位在移位时有着特别的处理,包括算术移位和逻辑移位两种类型。这在编写二分查找/线段树等含有大量除二操作的时候表现突出,有符号整数除法不能直接优化为一步右移位运算。
|
||||
|
||||
```c++
|
||||
int l, r;
|
||||
/* codes */
|
||||
int mid = (l + r) / 2; /* 如果编译器不能假定 l, r 非负,则会生成较差的代码 */
|
||||
// 不能优化为
|
||||
// mid = (l + r) >> 1
|
||||
// 反例:
|
||||
// mid = -127
|
||||
// mid / 2 = -63
|
||||
// mid >> 1 = -64
|
||||
```
|
||||
|
||||
```c++
|
||||
int mid = (l + r);
|
||||
int sign = mid >> 31; /* 逻辑右移, 得到符号位 */
|
||||
mid += sign;
|
||||
mid >>= 1; /* 算术右移 */
|
||||
```
|
||||
|
||||
可行的解决方案:
|
||||
|
||||
- 用 `unsigned l, r;`,下标本来就应该是无符号的
|
||||
- 在源代码中使用移位
|
||||
|
||||
##### 乘法代替除法
|
||||
|
||||
```cpp
|
||||
|
|
Loading…
Reference in New Issue