성능에 진정으로 관심이있는 경우 msb를 지우는 가장 좋은 방법은 최근 BMI 지침을 추가하여 x86에서 변경되었습니다. 86 어셈블리에서
: 정상적으로 BMI 명령어를 지원하지 않는 비의 x86 아키텍처 이상 x86 프로세서를 위해 분해하면서 이제
clear_msb:
bsrq %rdi, %rax
bzhiq %rax, %rdi, %rax
retq
는 C에 다시와 컴파일러 수 있도록하기 위해이 지침을 방출한다.
어셈블리 코드와 비교할 때 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 비트 명령어로 바뀝니다.
"단어의 가장 중요한 setted 비트"는 22 번째 비트입니까? 그게 내가 당신의 예제에서 볼 수있는 것 –
아니, 그것은 주어진 int에서 설정되는 가장 중요한 비트입니다. 0x12345678의 결과는 0x02345678입니다. 0x0000-> 0x00000023 – osgx
당신의 구현은 꽤 효율적입니다. 실제로 컴파일러가 빼기를 최적화하기 때문에 제 대답보다 훨씬 낫습니다. – hirschhornsalz