FPTAN 示例 x86
FPTAN Example x86
根据 Intel 文档,这就是 FPTAN
的作用:
Replace ST(0) with its approximate tangent and push 1 onto the FPU stack.
这是我在 NASM 中编写的代码:
section .data
fVal: dd 4
fSt0: dq 0.0
fSt1: dq 0.0
section .text
fldpi
fdiv dword[fVal] ; divide pi by 4 and store result in ST(0).
fptan
fstp qword[fSt0] ; store ST(0)
fstp qword[fSt1] ; store ST(1)
此时我发现fSt0
和fSt1
的值是:
fSt0 = 5.60479e+044
fSt1 = -1.#IND
但是,fSt0
和 fSt1
不应该都是 1
吗?
正如 Michael Petch 已经在评论中指出的那样,您有一个简单的错字。您没有将 fVal
声明为浮点值(如预期的那样),而是将其声明为 32 位整数。变化:
fVal: dd 4
至:
fVal: dd 4.0
那么您的代码将按预期工作。写对了。
如果您想要 接受整数输入,您可以通过更改代码以使用 FIDIV
指令来实现。该指令首先将整数转换为双精度浮点值,然后进行除法:
fldpi
fidiv dword [fVal] ; st(0) = pi / fVal
fptan ; st(0) = tan(st(0))
; st(1) = 1.0
fstp qword [fSt0]
fstp qword [fSt1]
但是因为需要转换,所以这比将输入作为浮点值的效率稍低。
请注意,如果您打算这样做,在某些较旧的 CPU 上分解负载会更有效,以便它与除法分开完成——例如,
fldpi
fild dword [fVal]
fdivp st(1), st(0) ; st(0) = pi / fVal
fptan ; st(0) = tan(st(0))
; st(1) = 1.0
fstp qword [fSt0]
fstp qword [fSt1]
换句话说,我们将 FIDIV
指令拆分为单独的 FILD
(整数加载)和 FDIVP
(分拆和弹出)指令。这改善了重叠,从而从代码的执行速度中削减了几个时钟周期。 (在较新的 CPU 上,从 AMD 系列 15h [Bulldozer] 和 Intel Pentium II 及更高版本 - 将 FIDIV
分解为 FILD
+FDIV
并没有真正的优势;无论哪种方式,你都应该性能相同。)
当然,因为这里的所有内容都是 常量,并且 tan(pi/4) == 1
,您的代码等同于:
fld1
fld1
…这是优化编译器会生成的。 :-)
根据 Intel 文档,这就是 FPTAN
的作用:
Replace ST(0) with its approximate tangent and push 1 onto the FPU stack.
这是我在 NASM 中编写的代码:
section .data
fVal: dd 4
fSt0: dq 0.0
fSt1: dq 0.0
section .text
fldpi
fdiv dword[fVal] ; divide pi by 4 and store result in ST(0).
fptan
fstp qword[fSt0] ; store ST(0)
fstp qword[fSt1] ; store ST(1)
此时我发现fSt0
和fSt1
的值是:
fSt0 = 5.60479e+044
fSt1 = -1.#IND
但是,fSt0
和 fSt1
不应该都是 1
吗?
正如 Michael Petch 已经在评论中指出的那样,您有一个简单的错字。您没有将 fVal
声明为浮点值(如预期的那样),而是将其声明为 32 位整数。变化:
fVal: dd 4
至:
fVal: dd 4.0
那么您的代码将按预期工作。写对了。
如果您想要 接受整数输入,您可以通过更改代码以使用 FIDIV
指令来实现。该指令首先将整数转换为双精度浮点值,然后进行除法:
fldpi
fidiv dword [fVal] ; st(0) = pi / fVal
fptan ; st(0) = tan(st(0))
; st(1) = 1.0
fstp qword [fSt0]
fstp qword [fSt1]
但是因为需要转换,所以这比将输入作为浮点值的效率稍低。
请注意,如果您打算这样做,在某些较旧的 CPU 上分解负载会更有效,以便它与除法分开完成——例如,
fldpi
fild dword [fVal]
fdivp st(1), st(0) ; st(0) = pi / fVal
fptan ; st(0) = tan(st(0))
; st(1) = 1.0
fstp qword [fSt0]
fstp qword [fSt1]
换句话说,我们将 FIDIV
指令拆分为单独的 FILD
(整数加载)和 FDIVP
(分拆和弹出)指令。这改善了重叠,从而从代码的执行速度中削减了几个时钟周期。 (在较新的 CPU 上,从 AMD 系列 15h [Bulldozer] 和 Intel Pentium II 及更高版本 - 将 FIDIV
分解为 FILD
+FDIV
并没有真正的优势;无论哪种方式,你都应该性能相同。)
当然,因为这里的所有内容都是 常量,并且 tan(pi/4) == 1
,您的代码等同于:
fld1
fld1
…这是优化编译器会生成的。 :-)