Code machine x87, 11 octets
D9 EB
DA 31
D9 F2
DD D8
DA 09
C3
Les octets de code ci-dessus définissent une fonction qui calcule l'aire d'un n-gon régulier avec un apothème de 1. Il utilise des instructions FPU x87 (l'unité à virgule flottante classique sur les processeurs x86) pour effectuer ce calcul.
Suivant une convention d'appel standard basée sur un registre x86 (dans ce cas, __fastcall
), l'argument de la fonction est un pointeur vers l'entier, passé dans le ECX
registre. Le résultat de la fonction est une valeur à virgule flottante, renvoyée en haut de la pile à virgule flottante x87 (registre ST0
).
Essayez-le en ligne!
Mnémoniques d'assemblage non golfés:
D9 EB fldpi ; load constant PI at top of FPU stack
DA 31 fidiv DWORD PTR [ecx] ; divide PI by integer input (loaded from pointer
; in ECX), leaving result at top of FPU stack
D9 F2 fptan ; compute tangent of value at top of FPU stack
DD D8 fstp st0 ; pop junk value (FPTAN pushes 1.0 onto stack)
DA 09 fimul DWORD PTR [ecx] ; multiply by integer input (again, loaded via ECX)
C3 ret ; return control to caller
Comme vous pouvez le voir, il s'agit essentiellement d'un calcul simple de la formule donnée,
résultat = n * tan (π / n)
Seules quelques choses intéressantes méritent d'être signalées:
- Le FPU x87 a une instruction dédiée pour charger la valeur constante PI (
FLDPI
). Cela était rarement utilisé, même dans la journée (et évidemment beaucoup moins maintenant), mais sa taille est plus courte que l'intégration d'une constante dans votre binaire et son chargement.
- L'instruction x87 FPU pour calculer la tangente,
FPTAN
remplace la valeur du registre d'entrée (le haut de la pile FPU) par le résultat, mais pousse également une constante 1.0 en haut de la pile FPU. Ceci est fait pour une compatibilité ascendante avec le 8087 (je n'ai aucune idée pourquoi cela a été fait sur le 8087; probablement un bug). Cela signifie que nous devons retirer cette valeur inutile de la pile. Le moyen le plus rapide et le plus court de le faire est simple FSTP st0
, comme nous l’utilisons ici. Nous aurions également pu faire une multiplication-et-pop , car la multiplication par 1.0 ne changera pas le résultat, mais cela représente également 2 octets (donc pas de gain en taille de code), s'exécutera probablement plus lentement et peut introduire une indétermination inutile dans le résultat.
Bien qu'un programmeur ou un compilateur moderne utilise le jeu d'instructions SSE (et versions ultérieures), plutôt que le x87 vieillissant, cela nécessiterait plus de code à implémenter, car il n'y a pas d'instruction unique pour calculer une tangente dans ces ISA plus récents.
Area@RegularPolygon
devrait êtreArea@*RegularPolygon
; tel qu'il est maintenant, il ne peut pas être capturé dans une variable. Autrement dit,f = Area@RegularPolygon; f[3]
ne fonctionne pas. Méta-discussion pertinente