x87机器代码,11个字节
D9 EB
DA 31
D9 F2
DD D8
DA 09
C3
上面的代码字节定义了一个函数,该函数计算1的正整数的正n边形的面积。它使用x87 FPU指令(x86处理器上的经典浮点单元)进行此计算。
遵循标准的基于x86基于寄存器的调用约定(在本例中为__fastcall
),该函数的参数是指向在ECX
寄存器中传递的整数的指针。该函数的结果是一个浮点值,在x87浮点堆栈(寄存器ST0
)的顶部返回。
在线尝试!
非高尔夫装配助记符:
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
如您所见,这基本上只是给定公式的简单计算,
结果= n * tan(π/ n)
仅指出了几件有趣的事情:
- x87 FPU具有用于加载常数值PI(
FLDPI
)的专用指令。它很少使用,甚至在今天也是如此(现在明显减少了),但是它的大小比将常量嵌入二进制文件并加载它要短。
- x87 FPU指令用于计算切线,
FPTAN
将结果替换输入寄存器的值(FPU堆栈的顶部),但还将常数1.0压入FPU堆栈的顶部。这样做是为了与8087向后兼容(我不知道为什么在8087上这样做;可能是一个错误)。这意味着我们需要将不需要的值从堆栈中弹出。最快和最短的方法是简单的FSTP st0
,就像我们在这里使用的那样。我们也可以做一个乘法和弹出操作,因为乘以1.0不会改变结果,但是这也是2个字节(因此,代码长度没有胜利),执行起来可能会更慢,并且可能导致不必要的不确定性结果。
尽管现代的程序员或编译器将使用SSE(及更高版本)指令集而不是老化的x87,但这将需要更多的代码来实现,因为在这些较新的ISA中没有一条指令可以计算切线。
Area@RegularPolygon
应该是Area@*RegularPolygon
; 现在,它不能被捕获到变量中。也就是说,f = Area@RegularPolygon; f[3]
不起作用。相关meta讨论