J'essaie d'estimer la complexité d'un algorithme que j'ai écrit pour le décompilateur Reko , où j'essaie de "défaire" la transformation effectuée par un compilateur en une division entière par une constante. Le compilateur a converti la division en une multiplication entière et un décalage:, où est le nombre de bits du mot machine de l'ordinateur. La multiplication constante qui en résulte est beaucoup plus rapide qu'une division dans la plupart des architectures contemporaines, mais ne ressemble plus au code d'origine.
Pour illustrer: l'instruction C
y = x / 10;
sera compilé par le compilateur Microsoft Visual C ++ dans le langage d'assemblage suivant
mov edx,1999999Ah ; load 1/10 * 2^32
imul eax ; edx:eax = dividend / 10 * 2 ^32
mov eax,edx ; eax = dividend / 10
Le résultat net est que le registre eax
aura désormais la valeur attendue du y
code source.
Un décompilateur naïf décompilera ce qui précède pour
eax = ((long)eax * 0x1999999A) >> 32;
mais Reko vise à rendre la sortie résultante plus lisible que celle en récupérant la constante qui était utilisée dans la division d'origine.
L'algorithme évoqué ci-dessus est basé sur la description de cet article dans Wikipedia . Tout d'abord, l'algorithme traite le multiplicateur constant comme la réciproque mise à l'échelle. Il convertit cela en un nombre à virgule flottante puis le réduit à , où . La dernière étape coûteuse consiste à mettre entre crochets la valeur en virgule flottante entre deux nombres rationnels , (en commençant par 0/1 et 1/1) et calculer à plusieurs reprises le médiant jusqu'à ce qu'un certain critère de convergence soit atteint. Le résultat devrait être la "meilleure" approximation rationnelle à l'inverse .
Maintenant, si le bracketing était fait avec une recherche binaire typique commençant entre les rationnels et et calculer le point médian , Je m'attends à ce que l'algorithme converge pas. Mais quelle est la complexité de l'algorithme si le médiant est utilisé à la place?
Réponses:
La relation entre l'arbre de Stern – Brocot et les séquences de Farey montre que si0<p/q<1 et (p,q)=1 (c'est à dire, p/q est une fraction réduite) puis p/q est au q niveau de l’arbre. Étant donné que le terme courant de votre algorithme est linéaire au niveau auquel vous terminez, votre algorithme prend du tempsO(q) , où p/q Est la réponse; mais ce n'est pas si utile.
Vous n'avez pas spécifié votre critère d'arrêt, mais vous avez probablement un certain seuil d'erreurϵ . La question est donc de savoir pour quelle séquence de Farey les termes adjacents sont au plus éloignés2ϵ (et donc chaque point est à distance ϵ à partir d'un certain point). En utilisant le fait que la distance entre les fractions adjacentesp1/q1,p2/q2 dans une séquence de Farey est 1/(q1q2) , il n'est pas difficile de montrer que la distance maximale au q e séquence de Farey est 1/q . Par conséquent, si vous visez à une distance deϵ , votre algorithme s'exécutera dans le temps O(1/ϵ) au pire des cas.
Cependant, "la plupart" des fractions adjacentesq Les séquences de Farey sont à distance O(1/q2) , et donc en moyenne, vous vous attendez probablement à une durée de O(1/ϵ−−−√) (malheureusement, cette moyenne concerne l'entrée plutôt que l'algorithme).
la source