Java中的快速整数除法
众所周知,整数除法运算速度慢(通常比整数乘法慢几倍)。但是,如果需要使用固定除数执行许多除法运算,可以对除数进行一些预处理,并用乘法和位运算替换“/”(中的第10章) 正如我所测试的,如果除数是编译时间常数,(例如,Java中的快速整数除法,java,performance,division,integer-division,Java,Performance,Division,Integer Division,众所周知,整数除法运算速度慢(通常比整数乘法慢几倍)。但是,如果需要使用固定除数执行许多除法运算,可以对除数进行一些预处理,并用乘法和位运算替换“/”(中的第10章) 正如我所测试的,如果除数是编译时间常数,(例如,static final long divisior=12345L;),JVM将使用乘法和位运算替换所有除法,并使用divisior。我对同样的技巧很感兴趣,但是除数只有在运行时才知道 例如,以下(慢速)方法: void reduceArraySlow(长[]数据,长分母){ 对于(
static final long divisior=12345L;
),JVM将使用乘法和位运算替换所有除法,并使用divisior
。我对同样的技巧很感兴趣,但是除数只有在运行时才知道
例如,以下(慢速)方法:
void reduceArraySlow(长[]数据,长分母){
对于(int i=0;i
可以用以下内容替换:
void reduceArrayFast(long[] data, long denominator){
SomeMagicStructure magic = computeMagic(denominator);
for(int i = 0; i < data.length; ++i)
// computes data[i] / denominator
data[i] = doFastDivision(data[i], magic);
}
void reduceArrayFast(长[]数据,长分母){
SomeMagicStructure magic=计算量(分母);
对于(int i=0;i
因为所有的/
操作都被更快的操作所取代(也因为除法在CPU中没有流水线)。有一个著名的C/C++快速整数除法库,这是我为Java改编的库
使用libdivide4j进行的快速除法如下所示:
void reduceArrayFast(long[] data, long denominator){
FastDivision.Magic magic = FastDivision.magicSigned(denominator);
for(int i = 0; i < data.length; ++i)
// computes data[i] / denominator
data[i] = FastDivision.divideSignedFast(data[i], magic);
}
void reduceArrayFast(long[] data, long denominator){
FastDivision.Magic magic = FastDivision.magicSigned(denominator);
for(int i = 0; i < data.length; ++i)
// computes data[i] / denominator
data[i] = FastDivision.divideSignedFast(data[i], magic);
}
public void benchmark() throws Exception {
Random rnd = new Random();
int nIterations = 10000;
//let the JIT to optimize something
for (int att = 0; att < nIterations; att++) {
long[] data = new long[1000];
for (int i = 0; i < data.length; i++)
data[i] = rnd.nextLong();
long denominator = rnd.nextLong();
long[] slow = data.clone();
long start = System.nanoTime();
reduceArraySlow(slow, denominator);
long slowTime = System.nanoTime() - start;
long[] fast = data.clone();
start = System.nanoTime();
reduceArrayFast(fast, denominator);
long fastTime = System.nanoTime() - start;
Assert.assertArrayEquals(slow, fast);
// print last 100 timings (JVM already warmed up)
if (att > nIterations - 100) {
System.out.println("\"/\" operation: " + slowTime);
System.out.println("Fast division: " + fastTime);
System.out.println("");
}
}
}
"/" operation: 13233
Fast division: 5957
"/" operation: 13148
Fast division: 5103
"/" operation: 13587
Fast division: 6188
"/" operation: 14173
Fast division: 6773
...