如果二进制数据的大小大于 32 位,如何“旋转”二进制数据(水平方向)?
How to “rotate” the binary data (in horizontal direction) if its size is greater than 32 bits?
我有以下 TypedArray(注意这个数据的大小是 80 位):
var arr = new Uint8Array([10, 110, 206, 117, 200, 35, 99, 2, 98, 125]);
我想将它旋转 N 位(其中 N 是 0 到 79 之间的任何整数)。比如N=50,我就这样表示:
00001010 01101110 11001110 01110101 11001000 00100011 01100011 00000010 01100010 01111101
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
所以结果应该是
01101100 01100000 01001100 01001111 10100001 01001101 11011001 11001110 10111001 00000100
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
所以arr[0]
将等于108,arr[1]
将等于96等。如何解决这个问题?
要按位移动整个字节数组,您可以这样做:
- 首先计算可以移动多少个字节(
var bytes = (bits / 8)|0;
)
- 从一端复制字节数,移动字节,将前一个切片粘贴到另一端
- 检查是否有剩余位(var remainder =
bits % 8
)
- 如果剩下任何余数 (!=0),则循环遍历、复制和移动前一个字节的相反方向的位数和剩余的 8 位 (
var prev = arr[arr.length - 1] << (8- remainder);
)(有关详细信息,请参见演示)。
- 移位字节并与前一个移位字节合并(
arr[i] = (arr[i]>>>remainder) | prev;
)
演示
// main rotation function
function rotate(arr, bits) {
var arrBits = arr.length<<3;
var aBits = Math.abs(bits) % arrBits; // "clamp" and make positive value
aBits = bits < 0 ? arrBits - aBits : aBits; // direction
var bytes = (aBits / 8)|0; // how many bytes we can pre-rotate
var remainder = aBits % 8; // number of additional bits that needs to rotate
var iRemainder = 8 - remainder; // inverse (cached for convenience)
var first; // first shift added to end
// first rotate based on number of whole bytes, get slice of end
var rBytes = arr.slice(arr.length - bytes);
// shift over remainding array byte-wise
arr.copyWithin(bytes, 0);
// set previous slice from end to beginning
arr.set(rBytes);
// shift remainders, if any (>0)
if (remainder) {
first = (arr[arr.length - 1] << iRemainder); // need this at the end
for(var i = arr.length-1; i > 0; i--) { // iterate in reverse
var prev = (arr[i - 1] << iRemainder); // get previous byte shifted
arr[i] = (arr[i]>>>remainder) | prev; // shift current, merge w/prev
}
arr[0] = (arr[0]>>>remainder) | first // shift last and merge w/first
}
}
// DEMO STUFF -
var rng = document.getElementById("bits");
var cnt = document.getElementById("cnt");
var out = document.getElementById("out");
function toBin(arr) {
for(var i=0, str="", str2=""; i < arr.length; i++) {
str+= pad(arr[i]) + " ";
str2 += arr[i].toString() + " ";
}
return str.replace(/0/g, "<span class=c>0</span>") + "<br>" + str2;
}
function pad(b) {
var s = "00000000" + b.toString(2);
return s.substr(s.length - 8)
}
function update() {
var arr = new Uint8Array([10, 110, 206, 117, 200, 35, 99, 2, 98, 125]);
cnt.innerHTML = rng.value; rotate(arr, +rng.value); out.innerHTML = toBin(arr)
}
update(); rng.oninput = update;
body {font:16px sans-serif;margin-left:0}
#out {font:12px monospace;white-space:nowrap}
.c {color:#999} div {margin-top:10px}
<label>Bits: <input id=bits type=range min=-80 max=80 value=0></label> <span id=cnt>0</span>
<div id=out></div>
要向相反方向旋转,只需从总位数中减去位数(arrayByteLength x 8 - 位),只需记住根据数组长度对结果应用模数即可。
我有以下 TypedArray(注意这个数据的大小是 80 位):
var arr = new Uint8Array([10, 110, 206, 117, 200, 35, 99, 2, 98, 125]);
我想将它旋转 N 位(其中 N 是 0 到 79 之间的任何整数)。比如N=50,我就这样表示:
00001010 01101110 11001110 01110101 11001000 00100011 01100011 00000010 01100010 01111101
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
所以结果应该是
01101100 01100000 01001100 01001111 10100001 01001101 11011001 11001110 10111001 00000100
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
所以arr[0]
将等于108,arr[1]
将等于96等。如何解决这个问题?
要按位移动整个字节数组,您可以这样做:
- 首先计算可以移动多少个字节(
var bytes = (bits / 8)|0;
) - 从一端复制字节数,移动字节,将前一个切片粘贴到另一端
- 检查是否有剩余位(var remainder =
bits % 8
) - 如果剩下任何余数 (!=0),则循环遍历、复制和移动前一个字节的相反方向的位数和剩余的 8 位 (
var prev = arr[arr.length - 1] << (8- remainder);
)(有关详细信息,请参见演示)。 - 移位字节并与前一个移位字节合并(
arr[i] = (arr[i]>>>remainder) | prev;
)
演示
// main rotation function
function rotate(arr, bits) {
var arrBits = arr.length<<3;
var aBits = Math.abs(bits) % arrBits; // "clamp" and make positive value
aBits = bits < 0 ? arrBits - aBits : aBits; // direction
var bytes = (aBits / 8)|0; // how many bytes we can pre-rotate
var remainder = aBits % 8; // number of additional bits that needs to rotate
var iRemainder = 8 - remainder; // inverse (cached for convenience)
var first; // first shift added to end
// first rotate based on number of whole bytes, get slice of end
var rBytes = arr.slice(arr.length - bytes);
// shift over remainding array byte-wise
arr.copyWithin(bytes, 0);
// set previous slice from end to beginning
arr.set(rBytes);
// shift remainders, if any (>0)
if (remainder) {
first = (arr[arr.length - 1] << iRemainder); // need this at the end
for(var i = arr.length-1; i > 0; i--) { // iterate in reverse
var prev = (arr[i - 1] << iRemainder); // get previous byte shifted
arr[i] = (arr[i]>>>remainder) | prev; // shift current, merge w/prev
}
arr[0] = (arr[0]>>>remainder) | first // shift last and merge w/first
}
}
// DEMO STUFF -
var rng = document.getElementById("bits");
var cnt = document.getElementById("cnt");
var out = document.getElementById("out");
function toBin(arr) {
for(var i=0, str="", str2=""; i < arr.length; i++) {
str+= pad(arr[i]) + " ";
str2 += arr[i].toString() + " ";
}
return str.replace(/0/g, "<span class=c>0</span>") + "<br>" + str2;
}
function pad(b) {
var s = "00000000" + b.toString(2);
return s.substr(s.length - 8)
}
function update() {
var arr = new Uint8Array([10, 110, 206, 117, 200, 35, 99, 2, 98, 125]);
cnt.innerHTML = rng.value; rotate(arr, +rng.value); out.innerHTML = toBin(arr)
}
update(); rng.oninput = update;
body {font:16px sans-serif;margin-left:0}
#out {font:12px monospace;white-space:nowrap}
.c {color:#999} div {margin-top:10px}
<label>Bits: <input id=bits type=range min=-80 max=80 value=0></label> <span id=cnt>0</span>
<div id=out></div>
要向相反方向旋转,只需从总位数中减去位数(arrayByteLength x 8 - 位),只需记住根据数组长度对结果应用模数即可。