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?