Я пытаюсь написать функцию, которая подсчитывает некоторые битовые флаги, избегая использования ветвления или условий:
uint8_t count_descriptors(uint8_t n)
{
return
((n & 2) && !(n & 1)) +
((n & 4) && !(n & 1)) +
((n & 8) && !(n & 1)) +
((n & 16) && !(n & 1)) +
((n & 32) && 1 ) +
((n & 64) || (n & 128)) ;
}
Нулевой бит напрямую не считается, а биты 1-4 учитываются только в том случае, если бит 0 не установлен, бит 5 считается безоговорочно, биты 6-7 могут считаться только один раз.
Однако я понимаю, что логические операторы && и || используйте оценку короткого замыкания. Это означает, что их использование создает условную ветвь, как вы могли бы видеть в таких примерах: if( ptr != nullptr && ptr->predicate())
, которая гарантирует, что код во втором подвыражении не будет выполнен, если результат вычисляется по короткому замыканию из первого подвыражения.
Первая часть вопроса: нужно ли что-то делать? Поскольку это чисто арифметические операции без побочных эффектов, будет ли компилятор создавать условные переходы?
Вторая часть: я понимаю, что побитовые логические операторы не закорачивают оценку, но единственная проблема - биты не выстраиваются. Результат маскирования n-го бита равен либо 2^n, либо нулю.
Как лучше всего сделать такое выражение, как (n & 16), равным 1 или 0?
(n & x) << x
даст вам 0 или 1 заx = 2^k
- person kmdreko   schedule 21.11.2017