Estou procurando um exemplo em que um algoritmo aparentemente está alterando sua classe de complexidade devido a estratégias de otimização de compilador e / ou processador.
c++
algorithms
optimization
big-o
Lorenz Lo Sauer
fonte
fonte
int main(void) { exit(0); };
Respostas:
Vamos usar um programa simples que imprima o quadrado de um número digitado na linha de comando.
Como você pode ver, este é um cálculo de O (n), repetindo repetidamente.
Ao compilar isso,
gcc -S
obtém-se um segmento que é:Neste você pode ver a adição sendo feita, uma comparação e um retorno ao loop.
Fazendo a compilação com
gcc -S -O3
para obter otimizações do segmento entre as chamadas para printf:Agora, pode-se ver que ele não tem loop e, além disso, não adiciona. Em vez disso, há uma chamada na
imull
qual multiplica o número por si só.O compilador reconheceu um loop e o operador matemático interno e o substituiu pelo cálculo apropriado.
Observe que isso incluiu uma chamada
atoi
para obter o número. Quando o número já existe no código, o complier pré-calcula o valor em vez de fazer chamadas reais, como demonstrado em uma comparação entre o desempenho do sqrt em C # e C em quesqrt(2)
(uma constante) foi somada em um loop 1.000.000 de vezes.fonte
A otimização de chamada de cauda pode reduzir a complexidade do espaço. Por exemplo, sem o TCO, essa implementação recursiva de um
while
loop tem uma complexidade de espaço no pior casoΟ(#iterations)
, enquanto que com o TCO tem uma complexidade de espaço no pior casoΟ(1)
:Isso nem precisa de TCO geral, apenas um caso especial muito estreito, a eliminação da recursão direta da cauda.
O que seria muito interessante, porém, é que a otimização do compilador não apenas altera a classe de complexidade, mas na verdade altera completamente o algoritmo.
O Glorioso Glasgow Haskell Compiler às vezes faz isso, mas isso não é realmente o que eu estou falando, isso é mais como fazer batota. O GHC possui uma linguagem de correspondência de padrões simples que permite ao desenvolvedor da biblioteca detectar alguns padrões de código simples e substituí-los por códigos diferentes. Ea implementação GHC da biblioteca padrão Haskell não conter algumas dessas anotações, para que usos específicos de funções específicas que são conhecidos por ser ineficiente são reescritas em versões mais eficientes.
No entanto, essas traduções são escritas por seres humanos e para casos específicos, é por isso que considero trapacear.
Um supercompilador pode ser capaz de alterar o algoritmo sem entrada humana, mas no AFAIK nenhum supercompilador em nível de produção foi criado.
fonte
Um compilador que está ciente de que a linguagem está usando big-num fazendo redução de força (substituindo multiplicações pelo índice de um loop por uma adição) alteraria a complexidade dessa multiplicação de O (n log n) na melhor das hipóteses para O (n) .
fonte