What's the fastest way to do a right bit rotation/circular shift on a byte array

[亡魂溺海] 提交于 2021-02-07 05:45:21

问题


If I have the array:

{01101111,11110000,00001111} // {111, 240, 15}

The result for a 1 bit shift is:

{10110111,11111000,00000111} // {183, 248, 7}

The array size is not fixed, and the shifting will be from 1 to 7 inclusive. Currently I have the following code (which works fine):

private static void shiftBitsRight(byte[] bytes, final int rightShifts) {
   assert rightShifts >= 1 && rightShifts <= 7;

   final int leftShifts = 8 - rightShifts;

   byte previousByte = bytes[0]; // keep the byte before modification
   bytes[0] = (byte) (((bytes[0] & 0xff) >> rightShifts) | ((bytes[bytes.length - 1] & 0xff) << leftShifts));
   for (int i = 1; i < bytes.length; i++) {
      byte tmp = bytes[i];
      bytes[i] = (byte) (((bytes[i] & 0xff) >> rightShifts) | ((previousByte & 0xff) << leftShifts));
      previousByte = tmp;
   }
}

Is there a faster way to achieve this than my current approach?


回答1:


The only way to find out is with thorough benchmarking, and the fastest implementations will vary from platform to platfrm. Use a tool like Caliper if you really need to optimize this.




回答2:


One of the things you can do is replace (byte[a]&0xff)>>b with byte[a]>>>b

Also, you don't need &0xff when you are left shifting.

Although it may not matter, either adding final to tmp or moving the declaration out of the loop may help a tiny bit.

Another thing might try is:

int tmp=bytes[bytes.length-1];
for (int i = bytes.length-2; i >=0; i--) {
  tmp=(tmp<<8)|bytes[i];
  bytes[i] = (byte) (tmp>>>rightShifts);
 }

Then you solve bytes[bytes.length-1] afterwards.

That reverse for loop may also help if you are superstitious. I've seen it work before.

Loop Analysis per pass:

yours: 3 assignments, two shifts, one or, one cast.

mine: 2 assignments, two shifts, one or, one cast.




回答3:


You can generalize this to longs and more than one bit shift if you like

// for a 1-bit rightshift:
// first rotate each byte right by one
for (i = 0; i < n; i++) b[i] = rotr(b[i], 1);
// get rightmost bit
bit = b[n-1] & 0x80;
// copy high order bit from adjacent byte
for (i = n; --i >= 1;){
    b[i] &= 0x7f;
    b[i] |= (b[i-1] & 0x80);
}
// put in the rightmost bit on the left
b[0] = (b[0] & 0x7f) | bit;

assuming rotr is defined.




回答4:


Use ByteBuffer.wrap to get a buffer that wraps your byte[] and then useByteBuffer.asLongBuffer() to get a view that allows you to extract and manipulate longs as suggested by @NiklasB. thus taking advantage of the hardware's ability to shift larger chunks of bits.



来源:https://stackoverflow.com/questions/9825319/whats-the-fastest-way-to-do-a-right-bit-rotation-circular-shift-on-a-byte-array

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!