编程中用移位运算替代乘除法会不会有问题?

2018-07-10 14:40:33 +08:00
 jssyxzy

因为移位运算实际上有算术移位,逻辑移位,循环移位;
又有有符号数,无符号数;
不同编程语言有可能实现不同。

请问这里面有没有什么坑?

10244 次点击
所在节点    程序员
80 条回复
jssyxzy
2018-07-10 21:33:58 +08:00
@rabbbit 嗯,位运算定义里面有如果移位数超过大小,结果是未定义的。
li1215101
2018-07-10 23:16:39 +08:00
写一句在后面要写一堆注释,过几天有人改了一下代码,忘记补注释就 gg
zjyl1994
2018-07-10 23:30:36 +08:00
你直接写乘除,剩下的让编译器来优化。现在不是 1980 年的电脑也不是那个年代的编译器了。
cs923
2018-07-10 23:51:03 +08:00
看 Java 的一些集合类源码也用到了位运算 应该能提升效率 也只是了解😄
shijingshijing
2018-07-11 00:37:35 +08:00
我比写编译器的人聪明系列。。。
msg7086
2018-07-11 00:55:39 +08:00
楼上几位说得也没错啊。
乘除法编译优化完本来就会变成其他玩意儿。
你写 a = a * 5,编译完就成 a = (a << 2) + a 了。
有符号无符号这些都是编译器帮你处理的。

又比如[1]
a = a / 19
编译完会变成
t = a * 2938661835 >> 32;
a = (t + ((a - t) >> 1) >> 4) & 0x0fffffff;

你问会不会有问题?会有问题啊。问题在你没编译器那么聪明严谨……

[1]: How do compilers optimize divisions? https://zneak.github.io/fcd/2017/02/19/divisions.html
zzj0311
2018-07-11 00:59:10 +08:00
csapp lab1,先去玩玩再说科学
tempdban
2018-07-11 01:47:18 +08:00
有用,有的情况必须写
上面的答案假设的情况不约而同都是用变量和常量做运算,折中情况编译器都能很好的优化。
都没考虑 第一个操作数 是变量 第二个操作数是个只要程序运行就能确定下来的变量
也就是说第二个变量初始化后就不会变。
最近性能优化大量的用了相关技巧 提升了 5%左右的性能 再加上其他优化手法,提升了 35%。
tempdban
2018-07-11 01:59:10 +08:00
楼上还有嘲讽“我比写编译器的人聪明系列”,大可不必这样。像我们这种一个任务需要执行几个指令周期都要细扣的领域,编译器的优化甚至有可能产生副作用。
很多代码写出来的效果很难看但是性能会爆炸的高。
你说的写法在特定的场合一定都是有用的,这里面会有坑尤其是,不同平台现象上会有差别,要多查多试。
知道什么时候该用而不是一棒子打死,你会领先很多人一个身位。
ericls
2018-07-11 02:05:08 +08:00
Linter 都过不了
chinvo
2018-07-11 02:46:19 +08:00
这是传说中的“只有我这种用汇编的人才见过世面”系列么?

不要为了追求“优化”滥用位移,降低代码可读性。

gcc 和 clang 现在已经默认启用 2 的幂乘除法到位移的优化,而在 py js java c# 之类的语言上同类优化机制也是存在的。不知道这些机制还非要强行开喷,怕不是不仅没见过世面连计算机科学基础都没学好。

或者大兄弟你还在用“先进的” VC++ 6.0 ?

至于在不存在自动优化或者刻意忽略 /禁用自动优化的情况下,写成位移对效率提升确实是有用的,但是必须自己处理溢出等问题。

明明就是个工程型(应用)的问题,非要扯什么“科学”(数理),还把楼上的诸位喷一个“没见过世面”,简直了。
gnaggnoyil
2018-07-11 03:17:40 +08:00
@jssyxzy 单片机?据我所知就算是 diab compiler,默认也会进行整数乘除至移位的优化,更不用说现在那么多单片机工具链不过就是 clang 换了层皮.而且既然你说到单片机,那看样子是在写 C/C++?C/C++里的整数的移位要么是确定的语义要么就是未定义行为,只要照着标准文档来就不会出现未预期的结果,除非 diab 或者 clang 有 bug.哪里有坑了?
yangqi
2018-07-11 03:47:06 +08:00
用之前先搞清楚为什么要用。
imn1
2018-07-11 04:35:08 +08:00
我写脚本用位运算不少,但不是为了优化
我更多是为了计算「位」
例如: $num >> 7 & 1
我目的是要知道$num 第八位是 1 还是 0,实际意义就是第八个权限:[ 有 | 无 ]
zwh2698
2018-07-11 07:17:47 +08:00
一般情况的场景,模拟器,虚拟机,部分算法,web 好像没有这个必要,因为上层已经将底层给包装了很多次,简单的区分一下,如果不是 c 或者 c plus 就基本用不着
bk201
2018-07-11 08:37:15 +08:00
看你什么工程了,视情况分析做程序员这个不懂说不过去.
proudzhu
2018-07-11 09:47:12 +08:00
负数处理结果不一致
hatsuyuki
2018-07-11 09:47:43 +08:00
移位比乘除效率高
nihiue
2018-07-11 09:57:27 +08:00
提前优化不可取,应该先完成功能,然后找出性能热点,针对性优化
shijingshijing
2018-07-11 09:59:41 +08:00
@tempdban 不知道你在那个平台上写的。

1,现代编译器普遍对乘法除法进行了优化,右移这种操作输入入门级的了。除非你手动强制关闭优化再换手写位移,这种情况有没有?我只见过很 PIC 单片机上做电机控制有这种操作。

2,现代 cpu 很多都集成了 FMA (也有叫 fmadd )的指令,包括 nvidia 的 gpu,一条 FMA 指令一次能完成一个加乘操作,使用 fma 指令只需要你把两个乘数放进去,然后把被加数置为 0,一个 cycle 后取结果即可。还需要你多花几个周期移来移去?

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/469591

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX