JAVA对于乘法除法和模运算的优化,是否需要转换成位运算
2015-04-21 15:23
363 查看
最近思考一个问题。我们知道,在底层汇编代码中,除以2的指令效率远低于直接右移1位。所以我看到的不止一个java教学视频(原谅我看了很多民间流传的教学视频,简单粗暴)说过/2尽量写成>>1。但是另一方面,我记得上课学过编译器的优化问题,很多事情其实是不需要程序员考虑的。那么事实是怎么样的呢?
这就要考虑到java编译的流程了:.java文件先转换成.class文件(字节码),在运行的时候,JVM先接收到字节码,再做JIT即时优化和编译,形成对应的机器码。
首先我想到的是,先查看一下.class文件的字节码,看看是否进行了优化:
最终看到的结果,除法被编译成了idiv,右移被编译成了ishr。就是说并没有优化。(如果是常数运算会直接在编译字节码时常量折叠,此处就不考虑了)
代码的测试结果也印证了这一点:
运算结果:
j=i/2; 1070ms
j=i>>1; 702ms
那么说到这里,为什么JVM没有把除法直接优化成右移呢,因为对于负数来说,右移不等于/2。举个例子:
-5 / 2 = -2
-5 >> 1 = -3
-5 >>> 1 = 2147483645
变量在编译期间如果再加一次正负数判断,往往是得不偿失的。因此:
对于乘法和以及%运算,JVM一定会优化,这些是不需要程序员去考虑的,直接去用*/%即可。
对于除法,因为上述问题,确实是位移更快些。
最后引申一下,虽然我们要“充分相信编译器”,但有些时候右移可能是最佳选择,例如java.util.Arrays.binarySearch:
这里用(low + high) >>> 1代替(low + high) /2是非常正确的,首先是因为数组下标肯定不会是负数,另一方面如果low + high大于int最大值(溢出变为负数了)时,只有>>>1能保证结果正确。
这就要考虑到java编译的流程了:.java文件先转换成.class文件(字节码),在运行的时候,JVM先接收到字节码,再做JIT即时优化和编译,形成对应的机器码。
首先我想到的是,先查看一下.class文件的字节码,看看是否进行了优化:
1 | javap -verbose 文件名 //这条指令可以反编译.calss文件,查看到具体指令。 |
代码的测试结果也印证了这一点:
12 | 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没有把除法直接优化成右移呢,因为对于负数来说,右移不等于/2。举个例子:
-5 / 2 = -2
-5 >> 1 = -3
-5 >>> 1 = 2147483645
变量在编译期间如果再加一次正负数判断,往往是得不偿失的。因此:
对于乘法和以及%运算,JVM一定会优化,这些是不需要程序员去考虑的,直接去用*/%即可。
对于除法,因为上述问题,确实是位移更快些。
最后引申一下,虽然我们要“充分相信编译器”,但有些时候右移可能是最佳选择,例如java.util.Arrays.binarySearch:
12 | int low = fromIndex; int high = toIndex - 1; while (low <= high) { int mid = (low + high) >>> 1; int midVal = a[mid]; if (midVal < key) low = mid + 1; else if (midVal > key) high = mid - 1; else return mid; // key found } return -(low + 1); // key not found. |
相关文章推荐
- 对于一个整数矩阵,存在一种运算,对矩阵中任意元素加一时,需要其相邻(上下左右)某一个元素也加一, 现给出一正数矩阵,判断其是否能够由一个全零矩阵经过上述运算得到。
- 对于一个整数矩阵,存在一种运算,对矩阵中任意元素加一时,需要其相邻(上下左右)某一个元素也加一,现给出一正数矩阵,判断其是否能够由一个全零矩阵经过上述运算得到
- 对于一个整数矩阵,存在一种运算,对矩阵中任意元素加一时,需要其相邻(上下左右)某一个元素也加一, 现给出一正数矩阵,判断其是否能够由一个全零矩阵经过上述运算得到。
- JAVA中对于需要频繁new的对象的一个优化的方法
- 对于一个整数矩阵,存在一种运算,对矩阵中任意元素加一时,需要其相邻(上下左右),某一个元素也加一,现给出一正数矩阵,判断其是否能够由一个全零矩阵经过上述运算得到。
- 对于一个整数矩阵,存在一种运算,对矩阵中任意元素加一时,需要其相邻(上下左右)某一个元素也加一, 现给出一正数矩阵,判断其是否能够由一个全零矩阵经过上述运算得到。
- 对于一个整数矩阵,存在一种运算,对矩阵中任意元素加一时,需要其相邻(上下左右)某一个元素也加一, 现给出一正数矩阵,判断其是否能够由一个全零矩阵经过上述运算得到。
- 对于一个整数矩阵,存在一种运算,对矩阵中任意元素加一时,需要其相邻(上下左右),某一个元素也加一,现给出一正数矩阵,判断其是否能够由一个全零矩阵经过上述运算得到。
- Java中基本数据类型的转换、原码和补码的表示及运算
- Java判断String是否是中文,并把中文转换成Unicode
- Java除法运算的陷阱
- JAVA1:数据类型(的转换)、常量变量与运算符
- 移位,逻辑运算实现加法,乘法和除法
- [转]java中byte转换int时为何与0xff进行与运算
- 类型转换问题(java会把byte,short和char的运算操作转换为int类型即低精度自动向高精度转换)
- java中byte转换int时为何与0xff进行与运算
- 【编程题目】对于一个整数矩阵,存在一种运算,对矩阵中任意元素加一时,需要其相邻(上下左右)某一个元素也加一
- Java微信二次开发之10-解析接口中的消息创建时间CreateTime 并转换成需要的格式
- java中byte转换int时为何与0xff进行与运算
- java中byte转换int时为何与0xff进行与运算(转)