Desafio C
Contar bits e inverter nibbles
Enunciado
Leia um inteiro sem sinal de 32 bits. Conte quantos bits estão ligados (popcount) sem usar funções de biblioteca. Em seguida, inverta a ordem dos quatro nibbles (grupos de 4 bits) e imprima o resultado em hexadecimal. Por fim, imprima o popcount do valor invertido.
Requisitos
- Implementar
count_bitscom laço ex &= x - 1. - Inverter nibbles usando shifts e máscaras.
- Imprimir os três valores: popcount original, valor invertido em hex, popcount invertido.
Código inicial
#include <stdio.h>
int count_bits(unsigned int x) {
// implemente
}
unsigned int reverse_nibbles(unsigned int x) {
// implemente
}
int main(void) {
unsigned int num;
scanf("%u", &num);
// use as funções e imprima
return 0;
}
Saída esperada
popcount original = 4
valor invertido = 0x1B
popcount invertido = 4
Ver dica
Para inverter nibbles, extraia cada nibble com (x >> shift) & 0xF e reposicione com << no lugar certo.
Mostrar solução
#include <stdio.h>
// Conta bits ligados sem funções de biblioteca
int count_bits(unsigned int x) {
int count = 0;
while (x) {
x &= x - 1; // remove o bit 1 mais baixo
count++;
}
return count;
}
// Inverte a ordem dos quatro nibbles de um inteiro de 32 bits
unsigned int reverse_nibbles(unsigned int x) {
unsigned int result = 0;
for (int i = 0; i < 4; i++) {
unsigned int nibble = (x >> (i * 4)) & 0xF; // extrai nibble i
result |= nibble << ((3 - i) * 4); // coloca na posição invertida
}
return result;
}
int main(void) {
unsigned int num;
scanf("%u", &num);
int pc_orig = count_bits(num);
unsigned int rev = reverse_nibbles(num);
int pc_rev = count_bits(rev);
printf("popcount original = %d\n", pc_orig);
printf("valor invertido = 0x%X\n", rev);
printf("popcount invertido = %d\n", pc_rev);
return 0;
}
Passo a passo
count_bitsusa o truquex &= x - 1, que apaga o bit 1 mais baixo. O laço executa exatamente o número de bits ligados.reverse_nibblespercorre os quatro nibbles (i = 0 a 3).- Para cada nibble,
(x >> (i * 4)) & 0xFisola os 4 bits na posiçãoi(0 = menos significativo). - Em seguida,
nibble << ((3 - i) * 4)move esse nibble para a posição invertida (nibble 0 vai para a posição 3, etc.). - O resultado é acumulado com
|=. - No
main, lemos o número, calculamos o popcount original, invertemos os nibbles, calculamos o popcount do invertido e imprimimos.
Por que funciona
A inversão de nibbles é uma permutação de grupos de 4 bits. Usando shifts e máscaras, extraímos cada grupo e o reposicionamos. O popcount com x &= x - 1 é eficiente porque cada iteração elimina um bit 1, independentemente de onde ele esteja. Juntas, essas técnicas mostram como manipular bits diretamente sem depender de funções prontas.
Erros comuns
- Usar
x >> (i * 4)sem máscara: isso traz bits indesejados dos nibbles superiores. O correto é& 0xF. - Confundir a ordem dos nibbles: o nibble 0 (bits 0-3) deve ir para a posição 3 (bits 12-15). Verifique com um exemplo pequeno.
- Em
count_bits, usarx >>= 1em vez dex &= x - 1: funciona, mas é menos eficiente e não demonstra o truque.
Outra forma de resolver
Pode-se inverter nibbles com uma tabela de lookup de 16 entradas, pré-calculando a inversão de cada nibble. Para 4 nibbles, a tabela é pequena e o código fica mais rápido, porém mais verboso.
Saída esperada
popcount original = 4
valor invertido = 0x1B
popcount invertido = 4