我在Java中编写一些代码,在某些时候,程序的流程是由两个int变量“a”和“b”是否非零决定的(注意:a和b从不为负,从不在整数溢出范围内)。
我可以评价它
if (a != 0 && b != 0) { /* Some code */ }
或者
if (a*b != 0) { /* Some code */ }
因为我期望这段代码每次运行数百万次,我想知道哪一个会更快。我做了一个实验,通过比较它们在一个巨大的随机生成的数组,我也很好奇,看看数组(数据分数= 0)的稀疏如何影响结果:
long time;
final int len = 50000000;
int arbitrary = 0;
int[][] nums = new int[2][len];
for (double fraction = 0 ; fraction <= 0.9 ; fraction += 0.0078125) {
for(int i = 0 ; i < 2 ; i++) {
for(int j = 0 ; j < len ; j++) {
double random = Math.random();
if(random < fraction) nums[i][j] = 0;
else nums[i][j] = (int) (random*15 + 1);
}
}
time = System.currentTimeMillis();
for(int i = 0 ; i < len ; i++) {
if( /*insert nums[0][i]*nums[1][i]!=0 or nums[0][i]!=0 && nums[1][i]!=0*/ ) arbitrary++;
}
System.out.println(System.currentTimeMillis() - time);
}
结果表明,如果你期望“a”或“b”等于0超过时间的〜3%,a * b!= 0比a!= 0& b!= 0:
我很想知道为什么。有人可以露出一些光吗?是编译器还是在硬件级?
编辑:出于好奇…现在我学到了分支预测,我想知道模拟比较将显示为OR b是非零:
我们确实看到分支预测与预期相同的效果,有趣的是,该图沿着X轴有些翻转。
更新
1-我添加了!(a == 0 || b == 0)到分析,看看会发生什么。
2-我也包括了!= 0 ||在学习关于分支预测之后,出于好奇,b!= 0,(a b)!= 0和(a | b)!但是它们在逻辑上不等同于其他表达式,因为只有OR b需要非零才能返回true,因此它们不会被用于比较处理效率。
3-我还添加了我用于分析的实际基准,它只是迭代一个任意的int变量。
有些人建议包括!= 0& b!= 0,而不是!= 0&& b!= 0,预测它将更接近a * b!= 0,因为我们将删除分支预测效果。我不知道&可以使用布尔变量,我认为它只用于与整数的二进制操作。
注意:在我正在考虑这一切的情况下,int溢出不是一个问题,但这绝对是一个重要的考虑在一般情况下。
CPU:Intel Core i7-3610QM @ 2.3GHz
Java版本:1.8.0_45
Java(TM)SE运行时环境(build 1.8.0_45-b14)
Java HotSpot(TM)64位服务器VM(构建25.45-b02,混合模式)