java怎样将乘法优化成位移乘法_JAVA对于乘法除法和模运算的优化,是否需要转换成位运算...

最近思考一个问题。我们知道,在底层汇编代码中,除以2的指令效率远低于直接右移1位。所以我看到的不止一个java教学视频(原谅我看了很多民间流传的教学视频,简单粗暴)说过/2尽量写成>>1。但是另一方面,我记得上课学过编译器的优化问题,很多事情其实是不需要程序员考虑的。那么事实是怎么样的呢?

这就要考虑到java编译的流程了:.java文件先转换成.class文件(字节码),在运行的时候,JVM先接收到字节码,再由JIT做即时优化和编译,形成对应的机器码。

首先我想到的是,先查看一下.class文件的字节码,看看是否进行了优化:

javac -p 文件名 //这条指令可以反编译.calss文件,查看到具体指令。

最终看到的结果,除法被编译成了idiv,右移被编译成了ishr。就是说并没有优化。

另外,我又尝试写了一些比较简单的带有冗余计算的代码,反编译之后发现同样没有优化,可以近似的认为编译到字节码是“直译”。

但是这并不能意味着/2的效率低于>>1,我用eclipse写代码尝试了一下:

long a1=System.currentTimeMillis();

for (long i = 0; i < 999999999l; i++) {

j=123456>>1;//或j=123456/2;

}

long a2=System.currentTimeMillis();

System.out.println(a2-a1);

多次运行发现:

j=i/2; 347ms

j=i>>1; 349ms

用javac直接编译运行发现结果相同。就是说,常数的位移操作和除法操作效率相同。

为此继续在stackoverflow查了一下资料,得到的结果毫无争议的都建议采用除法而不是位移,使用位移是一种premature optimization。因为JIT可以做到优化(不仅是除以2的乘方,任何数有可能会被拆成位移和加法的组合),而至于究竟是否会把除法变成位移取决于JVM所在环境的CPU类型,JVM通常来说都会选择最优的方式处理的。

参考资料:

http://stackoverflow.com/questions/1514949/quick-java-optimization-question

顺便再说一下。我把上面的代码稍作修改:

long a1=System.currentTimeMillis();

for (long i = 0; i < 999999999l; i++) {

j=i>>1;//或j=i/2;

}

long a2=System.currentTimeMillis();

System.out.println(a2-a1);

j=i/2; 1070ms

j=i>>1; 702ms

结果发现除法操作会比位移操作慢很多。原因在于对于负偶数,右移不等于除法。对于被除数是变量的情况下,并不会优化。

下面总结一下:

对于乘法和常量的除法以及%运算,JVM一定会优化,这些是不需要程序员去考虑的,直接去用*/%即可。

对于变量的除法,因为上述问题,确实是位移更快些。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值