为什么这段代码有几个“;或;语句比在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

在查看我昨天提出的一个微优化问题()时,我发现了一个奇怪的问题:Java中的
语句的运行速度比在布尔数组中查找布尔值的速度稍快

在我的测试中,在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为管理流程而增加的边界检查/其他开销。是的,这还不够重要,我不会改变我编写代码的方式或任何事情……我只是好奇,从知识的角度来看,为什么会这样。