что означает истинные условия при использовании побитового оператора

63
5

Вокруг порта js-кода я сталкиваюсь с трудностями при работе с побитовыми операциями.

Есть условие if, которое я не уверен, что полностью понимаю.

Условие, которое я не понимаю,

if (byteUnderConsideration & Math.pow(2, (7 - bitIndexWithinByte))) return node.right

Я не могу понять, когда это будет верно в этом случае.

Полный исходный код,

KBucket.prototype._determineNode = function (node, id, bitIndex) {
// **NOTE** remember that id is a Buffer and has granularity of
// bytes (8 bits), whereas the bitIndex is the _bit_ index (not byte)

// id that are too short are put in low bucket (1 byte = 8 bits)
// parseInt(bitIndex / 8) finds how many bytes the bitIndex describes
// bitIndex % 8 checks if we have extra bits beyond byte multiples
// if number of bytes is <= no. of bytes described by bitIndex and there
// are extra bits to consider, this means id has less bits than what
// bitIndex describes, id therefore is too short, and will be put in low
// bucket
var bytesDescribedByBitIndex = ~~(bitIndex / 8)
var bitIndexWithinByte = bitIndex % 8
if ((id.length <= bytesDescribedByBitIndex) && (bitIndexWithinByte !== 0)) return node.left

var byteUnderConsideration = id[bytesDescribedByBitIndex]

// byteUnderConsideration is an integer from 0 to 255 represented by 8 bits
// where 255 is 11111111 and 0 is 00000000
// in order to find out whether the bit at bitIndexWithinByte is set
// we construct Math.pow(2, (7 - bitIndexWithinByte)) which will consist
// of all bits being 0, with only one bit set to 1
// for example, if bitIndexWithinByte is 3, we will construct 00010000 by
// Math.pow(2, (7 - 3)) -> Math.pow(2, 4) -> 16
if (byteUnderConsideration & Math.pow(2, (7 - bitIndexWithinByte))) return node.right

return node.left
}

Портированный код,

func (K *KBucket) determineNode(node *KBucketNode, id []byte, bitIndex int) *KBucketNode {
if len(id) < 20 {
panic(fmt.Errorf("id length must be 20, got %v", id))
}
// **NOTE** remember that id is a Buffer and has granularity of
// bytes (8 bits), whereas the bitIndex is the _bit_ index (not byte)

// id that are too short are put in low bucket (1 byte = 8 bits)
// parseInt(bitIndex / 8) finds how many bytes the bitIndex describes
// bitIndex % 8 checks if we have extra bits beyond byte multiples
// if number of bytes is <= no. of bytes described by bitIndex and there
// are extra bits to consider, this means id has less bits than what
// bitIndex describes, id therefore is too short, and will be put in low
// bucket
bytesDescribedByBitIndex := int(math.Floor(float64(bitIndex) / 8))
bitIndexWithinByte := float64(bitIndex % 8)
if len(id) <= bytesDescribedByBitIndex && bitIndexWithinByte != 0 {
return node.left
}

byteUnderConsideration := id[bytesDescribedByBitIndex]

// byteUnderConsideration is an integer from 0 to 255 represented by 8 bits
// where 255 is 11111111 and 0 is 00000000
// in order to find out whether the bit at bitIndexWithinByte is set
// we construct Math.pow(2, (7 - bitIndexWithinByte)) which will consist
// of all bits being 0, with only one bit set to 1
// for example, if bitIndexWithinByte is 3, we will construct 00010000 by
// Math.pow(2, (7 - 3)) -> Math.pow(2, 4) -> 16
y := int(byteUnderConsideration) & int(math.Pow(2, (7-bitIndexWithinByte)))
if y > 0 {
return node.right
}

return node.left
}

Обычно я не выполняю такие вычисления, это все неясно, и я не могу правильно определить правильный способ их печати, чтобы начать понимать логику.

Спасибо!

спросил(а) 2021-01-25T19:20:13+03:00 4 месяца, 4 недели назад
1
Решение
77

Прежде всего, если вы работаете над битами, то вместо:

x * 8
x / 8

может быть:

x << 3
x >> 3

что сделает намерение более ясным.

Кроме того, не имеет смысла использовать:

byteUnderConsideration & Math.pow(2, (7 - bitIndexWithinByte))

когда вы можете сделать:

byteUnderConsideration & (1 << (7 - bitIndexWithinByte))

Что будет намного более ясно (не говоря уже о том, что это будет намного более эффективно).

Оператор << сдвигает биты влево и >> сдвигает вправо.

Оператор & AND имеет биты в одном и том же положении и | оператор ORs бит.

Вы действительно должны потратить некоторое время и прочитать о побитовых операторах в JavaScript (которые работают примерно так же, как в C), потому что вы делаете много странных конструкций, таких как:

~~(x / 8)

который может быть справедливым:

x >> 3

и ~~ (отрицание, сделанное дважды) не понадобилось бы, поскольку у вас уже было бы целое число. Кроме того, даже в тех случаях, когда вам нужно принудительно преобразовать целое число, вместо того, чтобы делать ~~x вам может быть лучше делать x|0 - см. Разницу между объединенным оператором ~~ и |0 здесь:

ответил(а) 2021-01-25T19:20:13+03:00 4 месяца, 4 недели назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема