在Java数组中置换位的最快方法

时间:2015-04-22 23:39:07

标签: java arrays permutation

随机(但重复)置换Java字节数组中所有位的最快方法是什么?我尝试使用BitSet成功完成它,但有更快的方法吗?显然,for循环占用了大部分的cpu时间。

我刚刚在IDE中进行了一些分析,for循环占整个permute()方法中64%的cpu时间。

为了澄清,数组(preRound)包含一个进入过程的现有数字数组。我希望该数组的各个设置位以随机方式混合。这就是P []的原因。它包含一个随机的位位置列表。因此,例如,如果设置了preRound的第13位,则将其转移到postRound的P [13]。这可能位于postRound的20555位置。整个事情是替换 - 置换网络的一部分,我正在寻找最快的方式来置换输入的比特。

我的代码到目前为止......

 private byte[] permute(byte[] preRound) {
    BitSet beforeBits = BitSet.valueOf(preRound);
    BitSet afterBits = new BitSet(blockSize * 8);


    for (int i = 0; i < blockSize * 8; i++) {
        assert i != P[i];


        if (beforeBits.get(i)) {
            afterBits.set(P[i]);
        }
    }


    byte[] postRound = afterBits.toByteArray();
    postRound = Arrays.copyOf(postRound, blockSize);      // Pad with 0s to the specified length
    assert postRound.length == blockSize;


    return postRound;
}

仅供参考,blockSize约为60,000,P是随机查询表。

1 个答案:

答案 0 :(得分:1)

我没有执行任何性能测试,但您可能需要考虑以下事项: 要省略对Arrays.copyOf的调用(它复制了整数使用的long []的副本,这有点令人讨厌),只需设置最后一位,以防它之前没有设置并在之后取消设置。

此外,有一个很好的习惯用法来迭代输入排列中的设置位。

private byte[] permute(final byte[] preRound) {
    final BitSet beforeBits = BitSet.valueOf(preRound);
    final BitSet afterBits = new BitSet(blockSize*8);
    for (int i = beforeBits.nextSetBit(0); i >= 0; i =
            beforeBits.nextSetBit(i + 1)) {
        final int to = P[i];
        assert i != to;
        afterBits.set(to);
    }
    final int lastIndex = blockSize*8-1;
    if (afterBits.get(lastIndex)) {
        return afterBits.toByteArray();
    }
    afterBits.set(lastIndex);
    final byte[] postRound = afterBits.toByteArray();
    postRound[blockSize - 1] &= 0x7F;
    return postRound;
}

如果它没有削减它,如果你使用相同的P进行大量迭代,那么考虑将置换转换为循环符号并就地执行转换可能是值得的。 这样你就可以线性迭代P,这可以让你更好地利用缓存(P是字节数组的32倍,假设它是一个int数组)。 然而,你将失去这样的优势:你只需要看1并最终在字节数组中的每个位移位,设置与否。

如果你想避免使用BitSet,你可以手动完成:

private byte[] permute(final byte[] preRound) {
    final byte[] result = new byte[blockSize];
    for (int i = 0; i < blockSize; i++) {
        final byte b = preRound[i];
        // if 1s are sparse, you may want to use this:
        // if ((byte) 0 == b) continue;
        for (int j = 0; j < 8; ++j) {
            if (0 != (b & (1 << j))) {
                final int loc = P[i * 8 + j];
                result[loc / 8] |= (1 << (loc % 8));
            }
        }
    }
    return result;
}