Bit reordenar twiddling
-
05-07-2019 - |
Pergunta
Eu preciso fazer um novo pedido arbitrário de um valor 7 bit (Sim, eu sei que eu deveria estar usando uma tabela) e estou querendo saber se existem hacks bit de fazer isso.
Exemplo:
// <b0, b1, b2, b3, b4, b5, b6> -> <b3, b2, b4, b1, b5, b0, b6>
// the naive way
out =
(0x020 & In) << 5 |
(0x008 & In) << 2 |
(0x040 & In) |
(0x012 & In) >> 1 |
(0x004 & In) >> 2 |
(0x001 & In) >> 3;
// 6 ANDs, 5 ORs, 5 shifts = 16 ops
edit: Eu estava pensando em algo ao longo das linhas de este
Apenas por diversão e porque eu estava AFTK Estou tentando uma pesquisa de força bruta para soluções da forma:
((In * C1) >> C2) & 0x7f
Não há soluções encontradas.
Solução
Tenha um olhar para a saída do compilador de código "ingênuo", pode surpreendê-lo. Uma vez eu fiz algo assim e o compilador (VC ++ 2005) mudou completamente os valores de todos os ands e mudanças para mim para torná-los mais eficientes, por exemplo, eu estou certo de que iria remover seu "(0x001 & In) >> 3" .
Mas sim, se a remodelação é uma função fixa, em seguida, uma mesa é provavelmente o melhor.
Atualizar
Para um riso Olhei para a saída do compilador de VC ++ 2005 ....
Primeiro eu tentei um valor constante para "In" mas o compilador não se deixou enganar um pouco, produziu este código:
mov eax,469h
ie. -lo completamente otimizado-lo afastado.
Então ... Eu tentei uma entrada adequada e tem o seguinte:
00401D4F mov eax,ecx
00401D51 and eax,20h
00401D54 shl eax,3
00401D57 mov edx,ecx
00401D59 and edx,8
00401D5C or eax,edx
00401D5E mov edx,ecx
00401D60 sar edx,1
00401D62 and edx,2
00401D65 or edx,ecx
00401D67 sar edx,1
00401D69 shl eax,2
00401D6C and edx,9
00401D6F or eax,edx
00401D71 and ecx,40h
00401D74 or eax,ecx
Isso é quatro operações de mudança, cinco ANDs, quatro RUP - nada mau para seis entradas. Provavelmente melhor do que a maioria das pessoas poderia fazer com a mão.
É, provavelmente, também otimizado para execução fora de ordem por isso vai ser ciclos de clock menos do que parece. : -)
Outras dicas
O primeiro passo parece ser a de compreender uma solução matemática e otimizar isso.
veja aqui de bit hacks
Há uma abundância de cortes-twiddling bit para operações comuns, isto é, para inverter a ordem dos bits de uma palavra de 32 bits (10 cada de deslocamento, AND e OR, AFAICR).
Neste caso, com um mapeamento aparentemente completamente arbitrária da entrada à saída, não posso ver nenhuma maneira de limpar isso.
Use uma tabela de pesquisa:)
Antes de otimizar, você deve certificar-se de seu caminho 'ingênuo' está fazendo o que você pretende. Se eu fizer o seu código em uma função e executar este loop:
for (b=0;b<7;b++)
{
i=1<<b;
printf("%d: %02x -> %02x\n", b, i, shuffle(i));
}
Ela produz esta saída, o que contradiz os comentários. Na verdade, ele perde pedaços.
0: 01 -> 00
1: 02 -> 01
2: 04 -> 01
3: 08 -> 20
4: 10 -> 08
5: 20 -> 00
6: 40 -> 40
A fim de obter o shuffle você descreve, gostaria de codificá-lo como este:
// 0 1 2 3 4 5 6
//-> 3 2 4 1 5 0 6
(0x001 & In) << 3 |
(0x004 & In) << 2 |
(0x020 & In) |
(0x012 & In) << 1 |
(0x008 & In) >> 2 |
(0x020 & In) >> 5 ;