Ваше основное уравнение:
c = b + (a << 8).
Хитрость в том, что вам нужно всегда сдвигаться на 8. Но так как a
и b
не всегда используют все 8 битов в байте,JavaScript автоматически пропускает любые ведущие нули.Нам нужно восстановить число ведущих нулей (b
) или конечных нулей a
и добавить их обратно перед добавлением.Таким образом, все биты остаются на своих местах.Для этого требуется следующее уравнение:
c = b + (a << s + r)
Где s
- это самый высокий установленный бит (идущий справа налево) в b
, а r
- это оставшееся количество битов, такое что s + r = 8
.
По сути, все, что вы делаете, это смещаете первый операнд a
на 8 бит, чтобы эффективно добавить конечные нули к a
или, в равной степени, дополняя ведущие нули вторым операндом b
.Потом добавляешь нормально.Это может быть выполнено с использованием логарифмов, сдвига и побитовой операции OR
, чтобы обеспечить решение O(1)
для некоторых произвольных положительных целых чисел a
и b
, где число битов в a
и b
не превышают некоторое положительное целое число n
.В случае байта n = 8
.
// Bitwise log base 2 in O(1) time
function log2(n) {
// Check if n > 0
let bits = 0;
if (n > 0xffff) {
n >>= 16;
bits = 0x10;
}
if (n > 0xff) {
n >>= 8;
bits |= 0x8;
}
if (n > 0xf) {
n >>= 4;
bits |= 0x4;
}
if (n > 0x3) {
n >>= 2;
bits |= 0x2;
}
if (n > 0x1) {
bits |= 0x1;
}
return bits;
}
// Computes the max set bit
// counting from the right to left starting
// at 0. For 20 (10100) we get bit # 4.
function msb(n) {
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
n = n + 1;
// We take the log here because
// n would otherwise be the largest
// magnitude of base 2. So, for 20,
// n+1 would be 16. Which, to
// find the number of bits to shift, we must
// take the log base 2
return log2(n >> 1);
}
// Operands
let a = 0b00001010 // 10
let b = 0b00010100 // 20
// Max number of bits in
// in binary number
let n = 8
// Max set bit is the 16 bit, which is in position
// 4. We will need to pad 4 more zeros
let s = msb(b)
// How many zeros to pad on the left
// 8 - 4 = 4
let r = Math.abs(n - s)
// Shift a over by the computed
// number of bits including padded zeros
let c = b + (a << s + r)
console.log(c)
Вывод:
2580
Примечания:
- Это НЕ коммутативно.
- Добавить проверку ошибок в log2 () для отрицательных чисел и других крайних случаев.
Ссылки: