Assembly 使用Nasm x86程序集计算平方根时输出不正确
首先,我要感谢所有读到这篇文章并试图帮助我解决这个问题的人,非常感谢 我正在编写一个汇编程序,用二分法计算IEEE-754格式的数字的平方根。我相信我对二分法的实现是正确的(尽管我可能会做得更有效),因为当我使用我的实现打印出一个数字的平方根,并从Assembly 使用Nasm x86程序集计算平方根时输出不正确,assembly,x86,nasm,square-root,bisection,Assembly,X86,Nasm,Square Root,Bisection,首先,我要感谢所有读到这篇文章并试图帮助我解决这个问题的人,非常感谢 我正在编写一个汇编程序,用二分法计算IEEE-754格式的数字的平方根。我相信我对二分法的实现是正确的(尽管我可能会做得更有效),因为当我使用我的实现打印出一个数字的平方根,并从fsqrt打印出FPU给我的平方根时,我得到了相同的结果,在这两种情况下,对于我尝试过的每个输入号码。所以这让我相信我打印的数字是错误的。我做错了什么 Here is the code: EXTERN printf EXTERN sscanf
fsqrt
打印出FPU给我的平方根时,我得到了相同的结果,在这两种情况下,对于我尝试过的每个输入号码。所以这让我相信我打印的数字是错误的。我做错了什么
Here is the code:
EXTERN printf
EXTERN sscanf
GLOBAL main
SEGMENT .data
n: DD 0 ; Storage for float
n_sqrt: DD 0
l_bound: DD 0
u_bound: DD 0
epsilon: DD 0x3727C5AC ; Error bound. IEEE 754 representation of 0.00001
midpoint: DD 0
format: DB "%f", 0
form: DB "%s", 10, 0
formh: DB "%f", 10, 0
outFormat: DB "The square root of %lf is: ", 0
fsqrtForm: DB "fsqrt(n) = %f", 10, 0
SEGMENT .text
main:
push ebp ; compose stack frame
mov ebp, esp
mov eax, [ebp + 12] ; eax = address of param table
finit ; initialize FPU stack
pushad ; preserve all registers before making a system call
push n ; store f.p. number in n
push format ; format at f.p.
push dword [eax+4] ; push the first command line parameter
call sscanf ; convert it to f.p., store it in n
add esp, 4*3
popad
fld dword [n] ; st0 = n
fld1 ; st0 = 1; st1 = n
fadd st1 ; st0 = n+1; st1 = n
fst dword [u_bound] ; u_bound = n+1; st0 = n+1 ; st1 = n
fld1 ; st0 = 1; st1 = n+1; st2 = n
fadd st0 ; st0 = 2; st1 = n+1; st2 = n
fdivr st1 ; st0 = (n+1)/2; st1 = n+1; st2 = n
fstp dword [midpoint] ; midpoint = (n+1)/2; st0 = n+1; st1 = n
fcompp ; clear st0 and st1
.L1:
fld dword [n] ; st0 = n
fld dword [midpoint] ; st0 = midpoint; st1 = n
fmul st0 ; st0 = midpoint*midpoint; st1 = n
fcomip st1 ; midpoint*midpoint < n ? ; st0 = n
jae .L2 ; NO
fstp st0 ; clear st0
fld dword [midpoint] ; st0 = midpoint
fstp dword [l_bound] ; l_bound = midpoint; clear st0
jmp .L3 ; continue
.L2: ; Else
fstp st0 ; clear st0
fld dword [midpoint] ; st0 = midpoint
fstp dword [u_bound] ; u_bound = midpoint
.L3: ; midpoint = (l_bound + u_bound)/2.0
fld dword [u_bound] ; st0 = u_bound
fld dword [l_bound] ; st0 = l_bound; st1 = u_bound
faddp st1, st0 ; st0 = l_bound + u_bound
fld1 ; st0 = 1; st1 = l_bound + u_bound
fadd st0 ; st0 = 2; st1 = l_bound + u_bound
fdivrp st1, st0 ; st0 = (l_bound + u_bound)/2.0
fstp dword [midpoint] ; midpoint = (l_bound + u_bound)/2.0 ; clear st0
fld dword [epsilon] ; st0 = epsilon
fld dword [u_bound] ; st0 = u_bound; st1 = epsilon
fld dword [l_bound] ; st0 = l_bound; st1 = u_bound; st2 = epsilon
fsubp st1, st0 ; st0 = u_bound - l_bound; st1 = epsilon
fcomip st1 ; check: is u_bound - l_bound > epsilon? st0 = epsilon
ja .L5 ; YES break while loop
fstp st0 ; NO - clear st0 and continue
jmp .L1
.L5:
jmp .printSqrt
.end:
pop ebp
ret
;---------------------------------------------------------------------------------------------------
.printSqrt:
fld dword [n]
sub esp, 8
fstp qword [esp]
push outFormat
call printf
add esp, 12
fld dword [midpoint]
sub esp, 8
fstp qword [esp]
push formh
call printf
add esp, 12
fld dword [n]
fsqrt
sub esp, 8
fstp dword [esp]
push fsqrtForm
call printf
add esp, 12
jmp .end
ret
以下是代码:
外部打印
外行
全球主要
段.数据
n:dd0;浮子贮存
n_sqrt:dd0
l_界:DD 0
u_界:DD 0
ε:DD 0x3727C5AC;错误界限。IEEE 754表示0.00001
中点:DD 0
格式:数据库“%f”,0
表格:数据库“%s”,10,0
格式:数据库“%f”,10,0
格式:DB“%lf的平方根为:”,0
fsqrtForm:DB“fsqrt(n)=%f”,10,0
段.文本
主要内容:
推动ebp;组合堆栈框架
电动汽车
mov-eax,[ebp+12];eax=参数表的地址
有限;初始化FPU堆栈
普沙德;在进行系统调用之前保留所有寄存器
推n;在n中存储f.p.编号
推送格式;格式为f.p。
推送双字[eax+4];按下第一个命令行参数
调用sscanf;将其转换为f.p.,存储在n中
添加esp,4*3
波帕德
弗尔德·德沃德[n];st0=n
fld1;st0=1;st1=n
faddst1;st0=n+1;st1=n
fst-dword[u_-bound];u_界=n+1;st0=n+1;st1=n
fld1;st0=1;st1=n+1;st2=n
faddst0;st0=2;st1=n+1;st2=n
fdivr-st1;st0=(n+1)/2;st1=n+1;st2=n
fstp dword[中点];中点=(n+1)/2;st0=n+1;st1=n
fcompp;清除st0和st1
.L1:
弗尔德·德沃德[n];st0=n
fld dword[中点];st0=中点;st1=n
fmulst0;st0=中点*中点;st1=n
fcomip st1;中点*中点ε?st0=ε
ja.L5;是的,边断边循环
fstp-st0;否-清除st0并继续
jmp.L1
.L5:
jmp.printSqrt
(完)
流行ebp
ret
;---------------------------------------------------------------------------------------------------
.printSqrt:
德沃德空军基地[n]
副esp,8
fstp-qword[esp]
推外格式
调用printf
添加esp,12
德沃德机场[中点]
副esp,8
fstp-qword[esp]
推式
调用printf
添加esp,12
德沃德空军基地[n]
fsqrt
副esp,8
德沃德
推送fsqrtForm
调用printf
添加esp,12
jmp.end
ret
[另外:输入编号作为命令行参数传递。]
再次感谢 从esp
esp
中减去8,但只在那里存储一个双字。试试看,我发现我有三个小问题:
1) 正如Frank提到的,当我保留8个字节时,我只在esp
中存储了一个dword,而不是qword
2) 在线:fdivrp st1、st0;st0=(l_绑定+u_绑定)/2.0
我将divrp
更改为divp
。让divrp
实际计算2.0/(l\u-bound+u\u-bound)
,这是我想要的东西的倒数
3) 我需要换衣服