La tâche est simple: écrire un assemblage qui calcule l'ordre de grandeur d'un entier en utilisant le moins de cycles d'horloge possible.
- L'ordre de grandeur est défini comme
log10
nonlog2
. - La plage d'entrées valides est
0
de , inclus. Le comportement pour l'entrée en dehors de cette plage n'est pas défini.1012
- Les valeurs doivent être arrondies à l'entier le plus proche, à l'exception de l'entrée donnée,
0
la sortie doit l'être0
. (Vous pouvez considérer que c'est la meilleure représentation de l'infini négatif possible dans les entiers non signés). - Doit être un assemblage x86.
- L'entier doit être une valeur d' exécution , pas un entier statique / en ligne. Nous ne savons donc pas ce que c'est au moment de la compilation.
- Supposons que vous avez déjà un entier chargé dans un registre. (Mais inclure la définition de la valeur dans le registre dans la réponse pour plus de clarté).
- Impossible d'appeler des bibliothèques ou des fonctions externes.
- Libre d'utiliser toutes les instructions disponibles dans la documentation Intel .
- Non C.
- N'importe laquelle des ~ 7 architectures Intel Core est acceptable (répertoriée à la page 10 ). Idéalement Nehalem (Intel Core i7).
La réponse gagnante est celle qui utilise le moins de cycles d'horloge possible. Autrement dit, il peut avoir le plus d'opérations par seconde. Les résumés approximatifs du cycle d'horloge sont ici: http://www.agner.org/optimize/instruction_tables.pdf . Le calcul des cycles d'horloge peut se produire après la publication de la réponse.
math
fastest-algorithm
assembly
Lance Pollard
la source
la source
Réponses:
7 cycles, temps constant
Voici une solution basée sur ma réponse à cette question SO . Il utilise BSR pour compter le nombre de bits nécessaires pour contenir le nombre. Il recherche le nombre de chiffres décimaux nécessaires pour représenter le plus grand nombre pouvant contenir de nombreux bits. Ensuite, il soustrait 1 si le nombre réel est inférieur à la puissance la plus proche de 10 avec autant de chiffres.
Compile sur GCC 4.6.3 pour ubuntu et renvoie la valeur dans le code de sortie.
Je ne suis pas sûr d'interpréter cette table de cycles pour n'importe quel processeur moderne, mais en utilisant la méthode de @ DigitalTrauma, sur le processeur Nehalim, j'obtiens 7 ?
la source
The integer must be a runtime value, not a static/inline integer. So we don't know what it is at compile time.
Meilleur cas 8 cycles, pire cas 12 cycles
Comme ce n'est pas clair dans la question, je fonde cela sur les latences d'Ivy Bridge.
L'approche ici consiste à utiliser l'
bsr
instruction (bit scan reverse) comme log2 () du pauvre. Le résultat est utilisé comme index dans une table de sauts qui contient des entrées pour les bits 0 à 42. Je suppose que, étant donné que l'opération sur les données 64 bits est implicitement requise, alors l'utilisation de l'bsr
instruction est OK.Dans le meilleur des cas, l'entrée jumptable peut mapper le
bsr
résultat directement à l'amplitude. Par exemple, pour les entrées dans la plage 32-63, lebsr
résultat sera 5, qui est mappé à une amplitude de 1. Dans ce cas, le chemin d'instruction est:Dans le pire des cas, les entrées
bsr
seront mappées à deux amplitudes possibles, de sorte que l'entrée de saut peut en faire une supplémentairecmp
pour vérifier si l'entrée est> 10 n . Par exemple, pour les entrées dans la plage 64-127, lebsr
résultat sera 6. L'entrée de pontage correspondante vérifie ensuite si l'entrée> 100 et définit la grandeur de sortie en conséquence.De plus, pour le pire des cas, nous avons une instruction mov supplémentaire pour charger une valeur immédiate de 64 bits à utiliser dans le
cmp
, donc le pire des instructions est:Voici le code:
Cela a été principalement généré à partir de la sortie de l'assembleur gcc pour le code C de preuve de concept que j'ai écrit . Notez que le code C utilise un goto calculable pour implémenter la table de saut. Il utilise également la fonction
__builtin_clzll()
intégrée gcc, qui compile l'bsr
instruction (plus unxor
).J'ai envisagé plusieurs solutions avant d'arriver à celle-ci:
FYL2X
pour calculer le logarithme naturel, puisFMUL
par la constante nécessaire. Ce serait probablement gagner si c'était un concours [tag: instruction: golf]. MaisFYL2X
a une latence de 90-106 pour Ivy bridge.Recherche binaire codée en dur. Cela peut en fait être compétitif - je laisse le soin à quelqu'un d'autre de l'implémenter :).
Tableau de recherche complet des résultats. Je suis sûr que cela est théoriquement le plus rapide, mais nécessiterait une table de recherche de 1 To - pas encore pratique - peut-être dans quelques années si la loi de Moore continue de tenir.
la source
jmp
etjcc
n'ont pas de latence, seulement des coûts de débit. La prédiction de branche + l'exécution spéculative signifie que les dépendances de contrôle ne font pas partie des chaînes de dépendance des données.