A tarefa é simples: escreva uma montagem que calcule a ordem de magnitude de um número inteiro usando o menor número possível de ciclos de relógio.
- Ordem de magnitude é definida como
log10
, nãolog2
. - O intervalo de entrada válido é
0
para , inclusive. O comportamento para entrada fora desse intervalo é indefinido.1012
- Os valores devem ser arredondados para o número inteiro mais próximo, com a exceção de que, dada a entrada,
0
a saída deve ser0
. (Você pode considerar que essa é a melhor representação do infinito negativo possível em números inteiros não assinados). - Deve ser uma montagem x86.
- O número inteiro deve ser um valor de tempo de execução , não um número inteiro estático / em linha. Portanto, não sabemos o que é em tempo de compilação.
- Suponha que você já tenha um número inteiro carregado em um registro. (Mas inclua a definição do valor no registro na resposta para maior clareza).
- Não é possível chamar nenhuma biblioteca ou função externa.
- Livre para usar qualquer uma das instruções disponíveis nos documentos da Intel .
- Não C.
- Qualquer uma das arquiteturas ~ 7 Intel Core é aceitável (listada na página 10 ). Idealmente Nehalem (Intel Core i7).
A resposta vencedora é aquela que usa o menor número possível de ciclos de relógio. Ou seja, ele pode ter o máximo de operações por segundo. Os resumos aproximados do ciclo do relógio estão aqui: http://www.agner.org/optimize/instruction_tables.pdf . O cálculo dos ciclos do relógio pode acontecer depois que a resposta for postada.
math
fastest-algorithm
assembly
Lance Pollard
fonte
fonte
Respostas:
7 ciclos, tempo constante
Aqui está uma solução com base na minha resposta a esta pergunta SO . Ele usa BSR para contar quantos bits são necessários para armazenar o número. Ele procura quantos dígitos decimais são necessários para representar o maior número que muitos bits podem conter. Subtrai 1 se o número real for menor que a potência mais próxima de 10 com tantos dígitos.
Compila no GCC 4.6.3 para ubuntu e retorna o valor no código de saída.
Não estou confiante em interpretar essa tabela de ciclos para qualquer processador moderno, mas usando o método da @ DigitalTrauma, no processador Nehalim, recebo 7 ?
fonte
The integer must be a runtime value, not a static/inline integer. So we don't know what it is at compile time.
Melhor caso 8 ciclos, pior caso 12 ciclos
Como não está claro na pergunta, estou baseando isso nas latências da Ivy Bridge.
A abordagem aqui é usar a
bsr
instrução (bit scan reverse) como um log2 de pobre (). O resultado é usado como um índice em uma tabela de salto que contém entradas para os bits de 0 a 42. Estou assumindo que, dado que a operação em dados de 64 bits é implicitamente necessária, o uso dabsr
instrução é OK.Na melhor das hipóteses, a entrada saltável pode mapear o
bsr
resultado diretamente para a magnitude. por exemplo, para entradas no intervalo 32-63, obsr
resultado será 5, que é mapeado para uma magnitude de 1. Nesse caso, o caminho da instrução é:Na pior das hipóteses, o
bsr
resultado será mapeado para duas magnitudes possíveis; portanto, a entrada saltável faz uma adicionalcmp
para verificar se a entrada é> 10 n . Por exemplo, para entradas na faixa de 64 a 127, obsr
resultado será 6. A entrada jumptable correspondente verifica se a entrada é> 100 e define a magnitude da saída de acordo.Além do caminho do pior caso, temos uma instrução mov adicional para carregar um valor imediato de 64 bits para uso no
cmp
, portanto, o caminho do pior caso é:Aqui está o código:
Isso foi gerado principalmente a partir da saída do montador gcc para o código C de prova de conceito que eu escrevi . Observe que o código C usa um goto computável para implementar a tabela de salto. Ele também usa o
__builtin_clzll()
gcc builtin, que é compilado com absr
instrução (mais umaxor
).Eu considerei várias soluções antes de chegar a esta:
FYL2X
para calcular o log natural e, em seguida,FMUL
pela constante necessária. Presumivelmente, isso venceria se fosse um concurso [tag: instruction: golf]. MasFYL2X
tem como latência de 90-106 para a ponte Ivy.Pesquisa binária codificada. Isso pode ser realmente competitivo - deixarei para outra pessoa implementar :).
Tabela de pesquisa completa de resultados. Eu tenho certeza que isso é teoricamente mais rápido, mas exigiria uma tabela de pesquisa de 1 TB - ainda não prática - talvez em alguns anos se a Lei de Moore continuar em vigor.
fonte
jmp
ejcc
não tem latência, apenas custos de taxa de transferência. Previsão de ramificação + execução especulativa significa que as dependências de controle não fazem parte das cadeias de dependência de dados.