Java中的快速整数除法

Java中的快速整数除法,java,performance,division,integer-division,Java,Performance,Division,Integer Division,众所周知,整数除法运算速度慢(通常比整数乘法慢几倍)。但是,如果需要使用固定除数执行许多除法运算,可以对除数进行一些预处理,并用乘法和位运算替换“/”(中的第10章) 正如我所测试的,如果除数是编译时间常数,(例如,static final long divisior=12345L;),JVM将使用乘法和位运算替换所有除法,并使用divisior。我对同样的技巧很感兴趣,但是除数只有在运行时才知道 例如,以下(慢速)方法: void reduceArraySlow(长[]数据,长分母){ 对于(

众所周知,整数除法运算速度慢(通常比整数乘法慢几倍)。但是,如果需要使用固定除数执行许多除法运算,可以对除数进行一些预处理,并用乘法和位运算替换“/”(中的第10章)

正如我所测试的,如果除数是编译时间常数,(例如,
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
...