So I finally figured out how to reverse 8-bits, 16-bits, and possibly 32-bits. However it doesn't appear to work in the 32-bit case in JavaScript. How do you do this in JavaScript using an optimized table-based approach?
Table Solution in 32 Bits
const BIT_REVERSAL_TABLE = new Array(256)
for (var i = 0; i < 256; ++i) {
var v = i, r = i, s = 7;
for (v >>>= 1; v; v >>>= 1) {
r <<= 1;
r |= v & 1;
--s;
}
BIT_REVERSAL_TABLE[i] = (r << s) & 0xff;
}
function reverseBits32(n) {
return (BIT_REVERSAL_TABLE[n & 0xff] << 24) |
(BIT_REVERSAL_TABLE[(n >>> 8) & 0xff] << 16) |
(BIT_REVERSAL_TABLE[(n >>> 16) & 0xff] << 8) |
BIT_REVERSAL_TABLE[(n >>> 24) & 0xff];
}
log32(0b11110010111110111100110010101011)
function log32(n) {
console.log(`${bits(n, 32)} => ${bits(reverseBits32(n), 32)}`)
}
function bits(n, size) {
return `0b${n.toString(2).padStart(size, '0')}`
}
Notice the logs are saying:
0b11110010111110111100110010101011 => 0b0-101010110011000010000010110001
When it should say:
0b11110010111110111100110010101011 => 0b11010101001100111101111101001111
Non-table Solutions in 32 Bits (that don't work)
// brev_knuth
function reverseBits32(a) {
let t
a = (a << 15) | (a >> 17);
t = (a ^ (a >> 10)) & 0x003f801f;
a = (t + (t << 10)) ^ a;
t = (a ^ (a >> 4)) & 0x0e038421;
a = (t + (t << 4)) ^ a;
t = (a ^ (a >> 2)) & 0x22488842;
a = (t + (t << 2)) ^ a;
return a;
}
function reverseBits32(x) {
x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1));
x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2));
x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4));
x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8));
return((x >> 16) | (x << 16));
}
I think these probably don't work because the bit-shifting creates a larger than 32-bit number? Not sure. Any hints would be appreciated.
Non-table Solution in 32 Bits (that works)
function reverseBits32(n) {
let res = 0;
for (let i = 0; i < 32; i++) {
res = (res << 1) + (n & 1);
n = n >>> 1;
}
return res >>> 0;
}
log32(0b11110010111110111100110010101011)
function log32(n) {
console.log(`${bits(n, 32)} => ${bits(reverseBits32(n), 32)}`)
}
function bits(n, size) {
return `0b${n.toString(2).padStart(size, '0')}`
}
First, why doesn't my 32-bit table solution work? Then, how can you make this work using the table approach in JavaScript (without using BigInt, and without using "convert to string and reverse" hacks) on a 32-bit integer?
I will note that this "BigInt 64" version in JavaScript works, so yay.
function reverseBits64(n) {
return (BigInt(BIT_REVERSAL_TABLE[Number(n & 255n)]) << 56n) |
(BigInt(BIT_REVERSAL_TABLE[Number((n >> 8n) & 255n)]) << 48n) |
(BigInt(BIT_REVERSAL_TABLE[Number((n >> 16n) & 255n)]) << 40n) |
(BigInt(BIT_REVERSAL_TABLE[Number((n >> 24n) & 255n)]) << 32n) |
(BigInt(BIT_REVERSAL_TABLE[Number((n >> 32n) & 255n)]) << 24n) |
(BigInt(BIT_REVERSAL_TABLE[Number((n >> 40n) & 255n)]) << 16n) |
(BigInt(BIT_REVERSAL_TABLE[Number((n >> 48n) & 255n)]) << 8n) |
BigInt(BIT_REVERSAL_TABLE[Number((n >> 56n) & 255n)]);
}
// 0b1111001011111011110011001010101111110010111110111100110010101011 =>
// 0b1101010100110011110111110100111111010101001100111101111101001111