为什么这段代码有几个“;或;语句比在Java中使用查找表稍微快一点?
在查看我昨天提出的一个微优化问题()时,我发现了一个奇怪的问题:Java中的为什么这段代码有几个“;或;语句比在Java中使用查找表稍微快一点?,java,optimization,Java,Optimization,在查看我昨天提出的一个微优化问题()时,我发现了一个奇怪的问题:Java中的或语句的运行速度比在布尔数组中查找布尔值的速度稍快 在我的测试中,在0到10亿的long值上运行以下算法,alg1大约快2%。(我改变了算法测试的顺序,得到了相同的结果)。我的问题是:为什么alg1更快?我本来希望alg2稍微快一点,因为它使用查找表,而alg1必须对75%的输入执行4个比较和3个or操作 private final static boolean alg1(long n) { int h = (int
或语句的运行速度比在布尔数组中查找布尔值的速度稍快
在我的测试中,在0到10亿的long
值上运行以下算法,alg1大约快2%。(我改变了算法测试的顺序,得到了相同的结果)。我的问题是:为什么alg1更快?我本来希望alg2稍微快一点,因为它使用查找表,而alg1必须对75%的输入执行4个比较和3个or操作
private final static boolean alg1(long n)
{
int h = (int)(n & 0xF);
if(h == 0 || h == 1 || h == 4 || h == 9)
{
long tst = (long)Math.sqrt(n);
return tst*tst == n;
}
return false;
}
private final static boolean[] lookup = new boolean[16];
static
{
lookup[0] = lookup[1] = lookup[4] = lookup[9] = true;
}
private final static boolean alg2(long n)
{
if(lookup[(int)(n & 0xF)])
{
long tst = (long)Math.sqrt(n);
return tst*tst == n;
}
else
return false;
}
如果您感到好奇,这段代码正在测试一个数字是否是一个完美的正方形,并利用了完美的正方形必须以0、1、4或9结尾的十六进制这一事实。根据数据,访问数组元素的成本是“访问非数组元素的2到3倍”。您的测试表明差异可能更大。我猜问题在于数组的范围检查,以及数组查找是否作为方法调用实现。这肯定会使4个整数的比较黯然失色。你看过字节码了吗?加载一些随机数据块通常比加载一点非分支代码要慢
当然,这完全取决于处理器体系结构。第一条if语句可以实现为四条指令。第二个可能需要空指针检查、边界检查以及加载和比较。另外,更多的代码意味着更多的编译时间,以及以某种方式进行优化的更多机会。这是一段有趣的代码,但2%的差异非常小。我不认为你能从中得出太多结论。在当前示例中,我同意边界检查可能是让你受益的原因(我无法理解JVM为什么不对此进行优化-示例代码可以确定地显示为不溢出
另一种可能性(尤其是较大的查找表)是缓存延迟…它取决于处理器寄存器的大小以及JVM如何选择使用它们-但是如果字节数组没有完全保留在处理器上,那么与简单的字节数组相比,或者当每次检查都将数组拉到CPU上时,您会看到性能下降。在处理器级别进行简单的查找通常是相当快的我想这是Java为管理流程而增加的边界检查/其他开销。是的,这还不够重要,我不会改变我编写代码的方式或任何事情……我只是好奇,从知识的角度来看,为什么会这样。