关于 for 循环中的 j - 1>=0 和 j > 0 的效率问题,太诡异了

2020-11-12 11:55:53 +08:00
 GTD

先看图,先用 j > 0 跑选择排序

然后改成 j - 1 >= 0,继续测试选择排序

这个算法一模一样,什么都没改,我跑了 30 多次,每次用 j - 1 > =0 都是 17 秒左右,而用 j >0 都在 16 秒左右,这两个效率怎么会有这么大差别,不应该啊。

而且我跑了 30 多次,每次都一样,一个是 16 秒,一个是 17 秒,只是小数点后不一样而已

3321 次点击
所在节点    Java
19 条回复
xuanbg
2020-11-12 11:59:58 +08:00
>=难道没有多跑一次吗?
GTD
2020-11-12 12:00:52 +08:00
@xuanbg #1 我跑了 30 多次,都是差不多一样,一个是 17 秒 一个是 16 秒
GTD
2020-11-12 12:01:20 +08:00
@xuanbg #1 哦哦,你说>=效率低一点,会多跑一次吗?
chendy
2020-11-12 12:27:52 +08:00
代码发出来大家试试?
v2yybb
2020-11-12 12:32:36 +08:00
j-1>=0;每次都计算 j-1,然后才判断.
j>0 的话 每次只判断
xiangyuecn
2020-11-12 12:32:48 +08:00
你理想中认为编译器是智能的,实机上编译器是一个智障。
chendy
2020-11-12 12:35:32 +08:00
多了一步减法,字节码多了一条 isub
大于小于 和 大于等于 小于等于 都是一条字节码,没区别
JeffGe
2020-11-12 12:36:54 +08:00
你要说 j - 1 >= 0 快,才叫诡异吧
no1xsyzy
2020-11-12 12:41:38 +08:00
( JVM 不清楚,按对 C - asm 的理解应该差不多吧)
j - 1 >= 0 是
取 j,取 1,相减,取 0,比较并跳转
j > 0 是
取 j,取 0,比较并跳转
即使理论上等效,但目前所有优化都是启发式的,不一定能发现最优解
guixiexiezou
2020-11-12 13:02:16 +08:00
所有 java 相关的,建议都热身后再跑测试,不然和你预想的有很大不一样
dazhangpan
2020-11-12 13:26:17 +08:00
不负责任地瞎猜是在分支条件这里的逻辑影响了 CPU 分支预测器的正确率
可以用 perf 抓一下看看 mispredict 的比例是不是上升了
lakehylia
2020-11-12 13:44:44 +08:00
试试 j - 1 >= 0 改成 j >= 1,看看时间是不是一样的。
GTD
2020-11-12 14:15:59 +08:00
@lakehylia #12 不行,刚刚试了一下,j >=1 还是一样,只有改成 j>0 才能 16s 左右
Mohanson
2020-11-12 14:37:09 +08:00
判断 j > 0 在 x86 上智商正常的编译器会用 jns 指令(Jump if not sign)而不会用比较跳转指令, 判断条件是 SF = 0

判断 j >= 1 在 x86 上用的是 jg 指令(Jump if greater), 判断条件是 ZF = 0 and SF = OF

以上是 gcc 的逻辑(我完全不会 java 也不知道 jvm 到底怎么操作的)
geelaw
2020-11-12 14:42:39 +08:00
显然 j - 1 >= 0 和 j > 0 是完全不同的意思,因为 Java 规定有符号数的溢出行为。如果 j = -2147483648,那么 j - 1 >= 0 是 true 而 j > 0 是 false 。

因此,编译器很难进行优化,故会采用先减后判断符号的方式,多做一次减法当然会慢。
lakehylia
2020-11-12 15:22:17 +08:00
@GTD 那结果就明显了,编译器在变量跟 0 的对比上有优化,而其他值没有。
misaka19000
2020-11-12 15:23:50 +08:00
直接看编译后的字节码,对比区别
XuanFei990
2020-11-12 17:23:53 +08:00
我以为下边的会短呢,那才奇怪。
多了一步减法操作吧,循环次数少,没什么感觉,循环次数多的话就产生明显差异了
Yantc
2020-11-12 17:44:09 +08:00
@GTD

j >=1:先做 j-1,再将 j-i 后的 ans 和 0 判断大小还要看是否存在溢出
j>0:直接将 j 的 bit 位或起来,就直接可判断,1:则 j 大于 0,0:则 j==0.

显然第二种情况快啊

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

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

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

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

© 2021 V2EX