为什么整数的java除法比黑客的喜悦实现更快
|
我正在测试来自黑客喜悦书的divs10函数吞吐量,在我的jdk 1.7 64bit版本21和i7 intel box上用
java编码
我想知道为什么默认的java运算符/比黑客的喜悦书中的divs10函数更快,结果显示divs10比“/”运算符慢3倍,令我惊讶. 任何人都可以告诉我,是否有任何花哨的内在jvm可以使用? 源代码如下. public class div10 {
public static final int divs10(int n) {
int q,r;
n = n + (n >> 31 & 9);
q = (n >> 1) + (n >> 2);
q += q >> 4;
q += q >> 8;
q += q >> 16;
q = q >> 3;
r = n - ((q << 3) + (q << 1));
return q + ((r + 6) >> 4);
}
public static void main(String[] args) {
/*
long count = 0;
for (int i = Integer.MIN_VALUE; i < Integer.MAX_VALUE; i++) {
if ( (i/10) != divs10(i) ) {
System.err.println("error dividing :" + i );
}
if ((i & 0xFFFFFFF ) == 0 ) {
System.out.println("Finished:" + Long.toHexString(count) + ":" + count + ":" + i);
}
count++;
}
System.out.println("Success:" + count);
*/
long start = System.nanoTime();
long count = 0L;
int iter = 100_000;
for (int j = 0; j < 10; j++)
for (int i = -iter; i < iter; i++) {
count += (i/10);
}
for (int j = 0; j < 10; j++)
for (int i = -iter; i < iter; i++) {
count += divs10(i);
}
System.out.println(count + " warm up done ") ;
start = System.nanoTime();
count = 0L;
for (int i = Integer.MIN_VALUE; i < Integer.MAX_VALUE; i++) {
count += i/10;
}
System.out.println(count + ",took:" + (System.nanoTime() - start) / 1000_000L + " ms," + (System.nanoTime() - start) / ((long)Integer.MAX_VALUE - (long)Integer.MIN_VALUE) + " ns per ops" ) ;
start = System.nanoTime();
count = 0L;
for (int i = Integer.MIN_VALUE; i < Integer.MAX_VALUE; i++) {
count += divs10(i);
}
System.out.println(count + "," + (System.nanoTime() - start) / ((long)Integer.MAX_VALUE - (long)Integer.MIN_VALUE) + " ns per ops" ) ;
}
}
解决方法更新:当查看较新的 Ivy Bridge table(第174页)时,我看到所有延迟都在1.这意味着我之前的解释是不正确的.计算在divs10方法中执行的指令的尝试是27(没有函数调用的开销)指令.您正在进行操作,要求在下一个操作开始之前完成前一个操作.这意味着您应该考虑指令的延迟.根据Ivy Bridge指令表,所涉及的所有指令都具有1个时钟周期的延迟.这总共给你27个时钟周期. 这与单个IDIV(8位)指令相比较.在表中,我发现这需要大约20个时钟周期的延迟. 原始估计将给出:27个周期/ 20个周期= 1.35倍慢.这与您的结果不一致.我不是这方面的专家,但我认为这是因为IDIV指令的划分可以并行运行,因为它们是独立的. IDIV指令的吞吐量为8个时钟周期.这允许CPU以这样的方式优化指令:它可以每52个周期运行大约4个分区(这是一个估计). 因此,要使用位移算法执行4次除法,您需要108个周期,而IDIV则需要大约64个时钟周期.这给出:108/52 =慢2.1倍. 这接近你测量的比率.我猜剩下的额外时间是函数调用的开销.也许CPU比我的估计做了更大的优化. (编辑:安卓应用网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
