x86汇编中如何除浮点数?
当我尝试编写 Heron 算法来从 ECX 寄存器计算 sqrt 时,它不起作用。看起来问题是除浮点数,因为结果是整数。
我的算法:
<前><代码> sqrtecx:
MOV EDX, 10 ; loop count
MOV EAX, 5 ; x_0 in heron algorythm
MOV DWORD[EBP-100], ECX ; save INPUT (ecx is input)
MOV DWORD[EBP-104], EDX ; save loop count
jmp loop
MOV ECX, EAX ; move OUTPUT to ECX
loop:
MOV DWORD[EBP-104], EDX ; save loop count
xor edx, edx
MOV ECX, EAX
MOV EAX, DWORD[EBP-100]
DIV ECX
ADD EAX, ECX
XOR EDX, EDX
mov ecx, 2
DIV ecx
MOV EDX, DWORD[EBP-104] ; load loop count
DEC EDX
JNZ loop
When i try to write Heron algorithm to count sqrt from ECX register, it doesn't work. It looks like the problem is dividing floating numbers, because the result is integer.
My algorithm:
sqrtecx:
MOV EDX, 10 ; loop count
MOV EAX, 5 ; x_0 in heron algorythm
MOV DWORD[EBP-100], ECX ; save INPUT (ecx is input)
MOV DWORD[EBP-104], EDX ; save loop count
jmp loop
MOV ECX, EAX ; move OUTPUT to ECX
loop:
MOV DWORD[EBP-104], EDX ; save loop count
xor edx, edx
MOV ECX, EAX
MOV EAX, DWORD[EBP-100]
DIV ECX
ADD EAX, ECX
XOR EDX, EDX
mov ecx, 2
DIV ecx
MOV EDX, DWORD[EBP-104] ; load loop count
DEC EDX
JNZ loop
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您需要使用浮点指令集来实现您的目标。您可能会发现有用的一些说明是:
这是一个简短的示例片段(VS2010 内联汇编):
编辑:
正如 harold 指出的,还有一个直接计算平方根的指令,它是 fsqrt。操作数和结果都是
st0
。编辑#2:
我不确定您是否真的可以将立即值加载到
st0
中作为我的 参考没有明确说明。因此,我做了一个小片段来检查,结果是:这些是
357A8h
处的字节:所以我必须得出结论,不幸的是,在加载时,您必须将数字存储在主内存中的某个位置并存储它们。当然,按照我上面的建议使用堆栈并不是强制性的,事实上您也可以在数据段或其他地方定义一些变量。
编辑#3:
别担心,汇编是一头难以击败的猛兽;)关于您的代码:
您缺少
fld
和fst
的操作数。看看你的评论,我想你想要fld [esp]
和fst [esp]
,我不明白你为什么在谈论ebp
> 不过。ebp
应该保存堆栈帧的开头(其中有很多我们不应该搞乱的东西),而esp
保存它的结尾。我们基本上希望在堆栈帧的末尾进行操作,因为在它之后只有垃圾没人关心。在计算并保存平方根后,您还应该在末尾添加 esp, 4。这是因为
push ecx
也在底层执行sub esp, 4
为您推送的值腾出空间,并且在保存值时您仍然需要一些空间。正因为如此,您还可以避免sub esp, 100
和add esp, 100
,因为房间已经通过push
为您准备好了.最后一个“警告”:整数和浮点值以非常不同的方式表示,因此当您知道必须使用这两种类型时,请小心您选择的指令。您建议的代码使用
fld
和fst
,它们都对浮点值进行操作,因此您得到的结果不会是您期望的结果。举个例子? 00 00 00 A9 是 169 的字节表示,但它表示浮点数 +2.3681944047089408e-0043 (对于挑剔的人来说,它实际上是一个 long double)。所以,最终的代码是:
You need to use the Floating Point Instruction Set to achieve your goal. Some instructions you might find useful are:
Here's a short example snippet (VS2010 inline assembly):
EDIT:
As harold pointed out, there's also an instruction which computes directly the square root, it is
fsqrt
. Both the operand and the result arest0
.EDIT #2:
I wasn't sure if you really could load into
st0
an immediate value as my reference doesn't specify if clearly. Therefore I did a small snippet to check and the result is:These are the bytes at
357A8h
:So I have to conclude that, unfortunately, you have to store your numbers somewhere in the main memory both when loading and storing them. Of course using the stack as I suggested above isn't mandatory, in fact you could also have some variables defined in your data segment or somewhere else.
EDIT #3:
Don't worry, assembly is a strong beast to beat ;) Regarding your code:
You're missing the operands of
fld
andfst
. Looking at your comments I suppose you wantedfld [esp]
andfst [esp]
, I don't get why you're talking aboutebp
though.ebp
is supposed to hold the beginning of the stack frame (where there's a lot of stuff which we shouldn't mess up with) whereasesp
holds the end of it. We basically want to operate at the end of the stack frame because after it there's just junk no one cares about.You should also
add esp, 4
at the end, after you computed and saved the square root. This becausepush ecx
does alsosub esp, 4
under the hood to make room for the value you push and you still need some room when saving the value back. It's just for this that you can also avoidsub esp, 100
andadd esp, 100
, because the room is already made for you bypush
.One last "warning": integers and floating point values are represented in very different ways, so when you know you have to use both types be careful about the instructions you choose. The code you suggested uses
fld
andfst
, which both operate on floating point values, so the result you get won't be what you expect it to be. An example? 00 00 00 A9 is the byte representation on 169, but it represents the floating point number +2.3681944047089408e-0043 (for the fussy people out there it is actually a long double).So, the final code is:
DIV
用于整数除法 - 您需要FDIV
进行浮点数(或者在这种特殊情况下更可能是FIDIV
,因为看起来您正在开始具有整数值)。DIV
is for integer division - you needFDIV
for floating point (or more likelyFIDIV
in this particular case, since it looks like you are starting with an integer value).我不完全确定您实际想要做什么,所以现在我假设您想要取整数的浮点平方根。
第一个
dword ptr
可能是可选的,具体取决于您的汇编器。执行此代码后,结果位于 FPU 堆栈的顶部 ST(0)。我不知道之后你想用它做什么..如果你想将它舍入为 int 并将其放回 ecx 中,我建议这样做:
我将采用 SSE2 方式作为良好的衡量标准:
这是一个这样容易一些。
I'm not completely sure what you actually want to do, so for now I'll assume that you want to take the floating-point square root of an integer.
The first
dword ptr
may be optional, depending on your assembler.After this code, the result is on the top of the FPU stack, ST(0). I don't know what you want to do with it afterwards.. if you want to round it to an int and put it back in ecx, I would suggest this:
I'll throw in the SSE2 way for good measure:
It's a bit easier that way.