当我尝试编写 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
最佳答案
您需要使用浮点指令集来实现您的目标。您可能会觉得有用的一些说明是:
fild <int> - loads and integer into st0 (not an immediate)
faddp - adds st0 to st1, and pop from reg stack (i.e. result in st0)
fdivp - divides st1 by st0, then pop from reg stack (again, push the result in st0)
这是一个简短的示例片段(VS2010 内联汇编):
int main(void)
{
float res;
__asm {
push dword ptr 5; // fild needs a memory location, the trick is
fild [esp]; // to use the stack as a temp. storage
fild [esp]; // now st0 and st1 both contain (float) 5
add esp, 4; // better not screw up the stack
fadd st(0), st(0); // st0 = st0 + st0 = 10
fdivp st(1), st(0); // st0 = st1 / st0 = 5 / 10 = 0.5
sub esp, 4; // again, let's make some room on the stack
fstp [esp]; // store the content of st0 into [esp]
pop eax; // get 0.5 off the stack
mov res, eax; // move it into res (main's local var)
add esp, 4; // preserve the stack
}
printf("res is %f", res); // write the result (0.5)
}
编辑:
正如 harold 指出的,还有一条直接计算平方根的指令,它是
fsqrt
.操作数和结果都是 st0
.编辑 #2:
我不确定你是否真的可以加载到
st0
立即值作为我的 reference没有说明是否清楚。因此我做了一个小片段来检查,结果是: float res = 5.0 * 3 - 1;
000313BE D9 05 A8 57 03 00 fld dword ptr [__real@41600000 (357A8h)]
000313C4 D9 5D F8 fstp dword ptr [res]
这些是
357A8h
处的字节:__real@41600000:
000357A8 00 00 add byte ptr [eax],al
000357AA 60 pushad
000357AB 41 inc ecx
所以我必须得出结论,不幸的是,在加载和存储数字时,您必须将数字存储在主存储器中的某个位置。当然,使用我上面建议的堆栈不是强制性的,事实上你也可以在你的数据段或其他地方定义一些变量。
编辑 #3:
别担心,汇编是一个强大的野兽;) 关于你的代码:
mov ecx, 169 ; the number with i wanna to root
sub esp, 100 ; i move esp for free space
push ecx ; i save value of ecx
add esp,4 ; push was move my ebp,then i must come back
fld ; i load from esp, then i should load ecx
fsqrt ; i sqrt it
fst ; i save it on ebp+100
add esp,100 ; back esp to ebp
您缺少
fld
的操作数和 fst
.看看你的评论,我想你想要 fld [esp]
和 fst [esp]
,我不明白你为什么在谈论 ebp
尽管。 ebp
应该保存堆栈帧的开头(那里有很多我们不应该弄乱的东西)而 esp
持有它的结束。我们基本上想在堆栈帧的末尾进行操作,因为在它之后只有没人关心的垃圾。您还应该
add esp, 4
最后,在您计算并保存平方根之后。这是因为 push ecx
也sub esp, 4
在引擎盖下为您推送的值腾出空间,并且在将值保存回来时仍然需要一些空间。正是为此,您还可以避免 sub esp, 100
和 add esp, 100
, 因为房间已经由 push
为您准备好了.最后一个“警告”:整数和浮点值以非常不同的方式表示,因此当您知道必须使用这两种类型时,请注意您选择的指令。您建议的代码使用
fld
和 fst
,它们都对浮点值进行运算,因此您得到的结果不会是您期望的结果。一个例子? 00 00 00 A9 是 169 上的字节表示,但它表示浮点数 +2.3681944047089408e-0043(对于那些挑剔的人来说,它实际上是一个长双)。所以,最终的代码是:
mov ecx, 169; // the number which we wanna root
push ecx; // save it on the stack
fild [esp]; // load into st0
fsqrt; // find the square root
fistp [esp]; // save it back on stack (as an integer)
// or fst [esp] for saving it as a float
pop ecx; // get it back in ecx
关于assembly - 如何在 x86 汇编中划分 float ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8804770/