Если вы действительно обеспокоены производительностью, лучший способ очистить msb недавно был изменен для x86 с добавлением инструкций BMI.
В сборке x86:
clear_msb:
bsrq %rdi, %rax
bzhiq %rax, %rdi, %rax
retq
Теперьпереписать на C и позволить компилятору испускать эти инструкции, в то же время изящно деградируя для архитектур не-x86 или более старых процессоров x86, которые не поддерживают инструкции BMI.
По сравнению с кодом сборки, версия C действительно уродлива иподробный.Но, по крайней мере, это отвечает цели мобильности.И если у вас есть необходимые аппаратные и компиляторные директивы (-mbmi, -mbmi2) для соответствия, вы вернетесь к прекрасному ассемблерному коду после компиляции.
Как написано, bsr () полагается на GCC / Clangвстроенный.Если вы нацелены на другие компиляторы, вы можете заменить их эквивалентным переносимым кодом C и / или другими встроенными компиляторами.
#include <inttypes.h>
#include <stdio.h>
uint64_t bsr(const uint64_t n)
{
return 63 - (uint64_t)__builtin_clzll(n);
}
uint64_t bzhi(const uint64_t n,
const uint64_t index)
{
const uint64_t leading = (uint64_t)1 << index;
const uint64_t keep_bits = leading - 1;
return n & keep_bits;
}
uint64_t clear_msb(const uint64_t n)
{
return bzhi(n, bsr(n));
}
int main(void)
{
uint64_t i;
for (i = 0; i < (uint64_t)1 << 16; ++i) {
printf("%" PRIu64 "\n", clear_msb(i));
}
return 0;
}
Обе версии сборки и C поддаются естественной замене 32-битными инструкциями, как оригиналбыл задан вопрос.