Eu uso uma variação de um filtro mediano de 5 cruzamentos nos dados de imagem em um pequeno sistema incorporado, ou seja,
x
x x x
x
O algoritmo é realmente simples: leia 5 valores inteiros não assinados, obtenha os 2 mais altos, faça alguns cálculos sobre esses valores e escreva novamente o resultado inteiro não assinado.
O interessante é que os 5 valores de entrada inteira estão todos no intervalo de 0 a 20. O valor inteiro calculado também está na faixa de 0 a 20!
Através da criação de perfil, eu descobri que obter os dois maiores números é o gargalo, por isso quero acelerar essa parte. Qual é a maneira mais rápida de realizar essa seleção?
O algoritmo atual usa uma máscara de 32 bits com 1 na posição fornecida pelos 5 números e uma função CLZ suportada por HW.
Devo dizer que a CPU é proprietária, não disponível fora da minha empresa. Meu compilador é o GCC, mas foi feito sob medida para esta CPU.
Tentei descobrir se posso usar uma tabela de pesquisa, mas não consegui gerar uma chave que possa usar.
Eu tenho combinações para a entrada, mas a ordem não é importante, ou seja, é a mesma que .[5,0,0,0,5]
[5,5,0,0,0]
Acontece que a função hash abaixo produz um hash perfeito sem colisões!
def hash(x):
h = 0
for i in x:
h = 33*h+i
return h
Mas o hash é enorme e simplesmente não há memória suficiente para usá-lo.
Existe um algoritmo melhor que eu possa usar? É possível resolver meu problema usando uma tabela de pesquisa e gerando uma chave?
fonte
hash
já realiza mais operações. As chamadas subseqüentes ao método estão relacionadas, por exemplo, a centralx
percorre a matriz linha por linha?Respostas:
Na minha outra resposta , sugiro que saltos condicionais possam ser o principal impedimento à eficiência. Como consequência, as redes de classificação vêm à mente: elas são independentes de dados, ou seja, a mesma sequência de comparações é executada independentemente da entrada, com apenas os swaps condicionais.
Obviamente, classificar pode ser muito trabalhoso; só precisamos dos dois maiores números. Para nossa sorte, as redes de seleção também foram estudadas. Knuth diz-nos que encontrar os dois números menores fora do five² pode ser feito com L 2 ( 5 ) = 6 comparações [1, 5.3.4 ex 19] (e, no máximo, como muitos swaps).você^2( 5 ) = 6
A rede que ele fornece nas soluções (reescrita para matrizes baseadas em zero) é
que implementa - após ajustar a direção das comparações - no pseudocódigo como
Agora, implementações ingênuas ainda têm saltos condicionais (através do código de troca). Dependendo da sua máquina, você pode contorná-las com instruções condicionais. x86 parece ser o habitual eu no poço da lama; O ARM parece mais promissor, pois aparentemente a maioria das operações é condicional em si mesma. Se eu entendi as instruções corretamente, a primeira troca se traduz nisso, supondo que nossos valores de matriz tenham sido carregados nos registros
R0
por meio deR4
:Sim, sim, é claro que você pode usar a troca de XOR com EOR .
Eu só espero que seu processador tenha isso ou algo semelhante. Obviamente, se você criar a coisa para esse fim, talvez consiga conectar a rede lá?
Este é provavelmente (provavelmente?) O melhor que você pode fazer no reino clássico, ou seja, sem fazer uso do domínio limitado e executar mágicas intrincadas em palavras.
fonte
Apenas para que fique sobre a mesa, aqui está um algoritmo direto:
Por uma implementação inteligente de
if ... else
, pode-se livrar de alguns saltos incondicionais que uma tradução direta teria.Isso é feio, mas leva apenas
Não se pode esperar que seja rápido em máquinas com tubulação; dado o alto percentual de saltos condicionais, a maior parte do tempo provavelmente seria gasta em estol.
Observe que uma variante mais simples - classifique
x1
ex2
, em seguida, insira os outros valores posteriormente - faz quatro a sete comparações e apenas cinco a seis atribuições. Como eu espero que os saltos sejam de custo mais alto aqui, fiquei com esse.fonte
Esse pode ser um ótimo aplicativo e caso de teste para o projeto Souper . O Souper é um super otimizador - uma ferramenta que utiliza uma curta sequência de código como entrada e tenta otimizá-lo o máximo possível (tenta encontrar uma sequência equivalente de código que será mais rápida).
Souper é um software livre. Você pode tentar executar o Souper no seu snippet de código para ver se ele pode melhorar.
Veja também o concurso de John Regehr para escrever código rápido para classificar 16 valores de 4 bits ; é possível que algumas das técnicas sejam úteis.
fonte
T[T[T[441*a+21*b+c]*21+d]*21+e]
fonte