Estou tentando estimar a complexidade de um algoritmo que escrevi para o descompilador Reko , onde estou tentando "desfazer" a transformação de um compilador em uma divisão inteira por uma constante . O compilador converteu a divisão em uma multiplicação de números inteiros e uma mudança: , em que é o número de bits da palavra-máquina do computador. A multiplicação constante resultante é muito mais rápida que uma divisão na maioria das arquiteturas contemporâneas, mas não se parece mais com o código original.
Para ilustrar: a instrução C
y = x / 10;
será compilado pelo compilador Microsoft Visual C ++ para a seguinte linguagem assembly
mov edx,1999999Ah ; load 1/10 * 2^32
imul eax ; edx:eax = dividend / 10 * 2 ^32
mov eax,edx ; eax = dividend / 10
O resultado líquido é que o registro eax
agora terá o valor esperado a y
partir do código-fonte.
Um descompilador ingênuo descompilará o acima
eax = ((long)eax * 0x1999999A) >> 32;
mas Reko pretende tornar a saída resultante mais legível do que a recuperando a constante usada na divisão original.
O algoritmo sugerido acima é baseado na descrição deste artigo na Wikipedia . Primeiro, o algoritmo trata o multiplicador constante como o valor recíproco em escala. Ele converte isso em um número de ponto flutuante e depois reduz a escala para , Onde . A etapa final e cara é colocar o valor do ponto flutuante entre parênteses entre dois números racionais , (começando com 0/1 e 1/1) e calcule repetidamente o mediant até que algum critério de convergência seja alcançado. O resultado deve ser a "melhor" aproximação racional ao recíproco .
Agora, se o bracketing estivesse sendo feito com uma pesquisa binária típica iniciando entre os racionais e e computando o ponto médio , Espero que o algoritmo converja passos. Mas qual é a complexidade do algoritmo se a mediante for usada?
fonte
Respostas:
A relação entre a árvore de Stern – Brocot e as seqüências de Farey mostra que, se0<p/q<1 e (p,q)=1 (ou seja, p/q é uma fração reduzida) então p/q é no q th nível da árvore. Como o prazo de execução do seu algoritmo é linear no nível em que você termina, seu algoritmo leva tempoO(q) , Onde p/q é a resposta; mas isso não é tão útil.
Você não especificou qual é o seu critério de parada, mas presumivelmente você tem algum limite de erroϵ . Portanto, a pergunta é para qual sequência de Farey é que os termos adjacentes estão à distância, no máximo.2ϵ (e todos os pontos estão à distância ϵ de algum ponto). Usando o fato de que a distância entre frações adjacentesp1/q1,p2/q2 em uma sequência do Farey é 1/(q1q2) , não é difícil mostrar que a distância máxima na q a sequência Farey é 1/q . Portanto, se você está buscando uma distância deϵ , seu algoritmo será executado a tempo O(1/ϵ) no pior dos casos.
Entretanto, "a maioria" de frações adjacentes noq A sequência do Farey está à distância O(1/q2) e, portanto, em média, você provavelmente esperaria um tempo de execução de O(1/ϵ−−−√) (infelizmente, essa média é mais relativa à entrada do que ao algoritmo).
fonte