我试图对x86上的浮点运算有一个基本的了解.我知道我们有一个带有堆栈的专用FPU,但是我没有找到关于堆栈在不同指令方面的行为方式的相关信息.
基本上,fpu寄存器的寻址让我很困惑.如果我参考st(#),我是在谈论一个特定的寄存器吗?或者它是从堆栈顶部偏移?
我想我的大多数问题都可以通过这个例子来回答:
如果我有一个空的FPU堆栈,并运行:
fld x
fld y
fmul st, st(1)
Run Code Online (Sandbox Code Playgroud)
结果会是:
ST(0) = y * x
ST(1) = x
Run Code Online (Sandbox Code Playgroud)
要么:
ST(0) = x * y
ST(1) = y
Run Code Online (Sandbox Code Playgroud)
?
注意,它们之间的差异是ST(1)中的值.
我创建了一个应用程序来计算64位范围内的素数,所以当我尝试使用i的sqrt函数计算64位数的平方根时,math.h发现答案是不准确的,例如当输入是~0ull答案应该是~0u但是我得到的是0x100000000哪个不对,所以我决定用汇编x86语言创建我自己的版本,看看这是不是一个bug,这是我的函数:
inline unsigned prime_isqrt(unsigned long long value)
{
const unsigned one = 1;
const unsigned two = 2;
__asm
{
test dword ptr [value+4], 0x80000000
jz ZERO
mov eax, dword ptr [value]
mov ecx, dword ptr [value + 4]
shrd eax, ecx, 1
shr ecx, 1
mov dword ptr [value],eax
mov dword ptr [value+4],ecx
fild value
fimul two
fiadd one
jmp REST
ZERO:
fild value
REST:
fsqrt
fisttp value
mov …Run Code Online (Sandbox Code Playgroud) Hullo,我正在学习x86 FPU汇编,我有一个简单的问题,我找不到答案:
如何将值从ST(0)(FPU堆栈顶部)移动到EAX?
还有:
这段代码是否正确:
; multiply (dot) two vectors of 3 floats passed by pointers as arg 1 arg 2
; passings are ok I think, but not sure if multiplies-adds are ok
push ebp
mov ebp, esp
mov eax, dword [ebp+8H]
mov edx, dword [ebp+0CH]
fld qword [eax]
fmul qword [edx]
fld qword [eax+4H]
fmul qword [edx+4H]
fld qword [eax+8H]
fmul qword [edx+8H]
faddp st1, st(0)
faddp st1, st(0)
fstp qword [ebp+10H] ; here …Run Code Online (Sandbox Code Playgroud) 我如何添加1或2注册xmm0(双)?
我可以这样做,但肯定必须有一个更简单的方法:
movsd xmm0, [ecx] xor eax, eax inc eax cvtsi2sd xmm1, eax addsd xmm0, xmm1 movsd [ecx], xmm0
还可以使用浮点x87指令执行此操作吗?
这对我不起作用:
fld dword ptr [ecx] fld1 faddp fstp dword ptr [ecx]
我正在尝试使用8086处理器编写汇编程序,该处理器将找到数字的立方根.显然我使用的是浮点数.
root := 1.0;
repeat
oldRoot := root;
root := (2.0*root + x/(root*root)) / 3.0
until ( |root – oldRoot| < 0.001;
Run Code Online (Sandbox Code Playgroud)
如何将(2*root + x)除以(root*root)?
.586
.MODEL FLAT
.STACK 4096
.DATA
root REAL4 1.0
oldRoot REAL4 2.0
Two REAL4 2.0
inttwo DWORD 2
itThree DWORD 3
three REAL4 3.0
x DOWRD 27
.CODE
main PROC
finit ; initialize FPU
fld root ; root in ST
fmul two ; root*two
fadd x ; root*two+27
fld root ; root …Run Code Online (Sandbox Code Playgroud) 英特尔指令参考中提供了以下文档以供参考COMISD:
在操作数1(第一个操作数)的低四字比较双精度浮点值和操作数2(第二个操作数),并设定了
ZF,PF和CF在EFLAGS标志寄存器根据结果(无序,大于,小于大于或等于)。
的CF的标志点是不是真的在这里清除,因为它关系到算术运算的无符号整数。相反,文档关注的是按定义签名的浮点。我进行了一些实验,例如
mov rax, 0x123
movq xmm0, rax
mov rax, 0x124
movq xmm1, rax
ucomisd xmm0, xmm1 ;CF is set here like if
;we would compare uints 0x123 and 0x124
Run Code Online (Sandbox Code Playgroud)
因此,当将操作数设置为双精度浮点时,该指令会将操作数设置为进位标志时,会将操作数视为无符号整数?
在我看来,这有点奇怪。
我知道SSE是x87浮点指令的替代品,但x87 FPU仍然在现代CPU中实现,如Ivy-Bridge或Haswell?
SSE是否取代了x87指令集?
我有这段代码,应该添加两个数字,一个浮点数(3.25)和一个整数(2)。
编辑:
extern _printf, _scanf
global _main
section .bss
num1: resb 4
section .data
format_num: db "%f", 10, 0
section .text
_main:
mov dword [num1], __float32__(3.25)
add num1, 2
sub esp, 8
fld dword [num1]
mov dword [num1], eax
fstp qword [esp]
push format_num
call _printf
add esp, 12
ret
Run Code Online (Sandbox Code Playgroud)
我得到的输出是:
test.asm:11:错误:操作码和操作数的组合无效
我期望的输出是:
5.250000
以下是使用FLD时可能出现的异常:
#IS发生堆栈下溢或溢出。#IA源操作数是 SNaN。如果源操作数是双扩展精度浮点格式(FLD m80fp 或 FLD ST(i)),则不会发生。#D源操作数是一个非正规值。如果源操作数是双扩展精度浮点格式,则不会发生。
为什么 #IA 异常“如果源操作数是双扩展精度浮点格式,则不会发生”?
我认为双精度浮点和双扩展精度浮点格式基本相同。两者都能够编码 SNaN。
这种差异是否有任何合乎逻辑的原因,或者只是它的方式?
8086/8087/8088 宏汇编语言参考手册 (c) 1980 Intel Corporation 提到(重点是我的):
... 8087 提供了非常好的实数系统近似值。然而,重要的是要记住,它不是精确的表示,并且实数的算术本质上是近似的。
相反,同样重要的是,8087 确实对其实数的整数子集执行精确算术。也就是说,对两个整数进行运算会返回精确的积分结果,前提是真实结果是整数并且在 range 内。
最近的手册更加简洁(强调他们的):
IA 处理器...它们可以处理最多 18 位的十进制数,而不会出现舍入错误,对大至 2^64(或 10^18)的整数执行精确算术。
FPU 支持的整数数据类型包括有符号字(16 位)、有符号双字(32 位)和有符号 qword(64 位)。从来没有提到过 UNsigned。事实上,FPU 的一切都带有符号性,甚至支持带符号零(+0 和 -0)。
那么,是否可以使用 FPU 将几个无符号64 位数字相除并得到精确的商和余数?
对于几个有符号64 位数字的除法,我编写了下面的代码。商看起来不错,但余数总是返回零。为什么是这样?
; IN (edx:eax,ecx:ebx) OUT (edx:eax,ecx:ebx,CF)
FiDiv: push edi ecx ebx edx eax
mov edi, esp
fninit
fild qword [edi] ; Dividend
fild qword [edi+8] ; Divisor
fld
fnstcw [edi]
or word [edi], 0C00h ; Truncate Towards …Run Code Online (Sandbox Code Playgroud)