Assembly 使用Nasm x86程序集计算平方根时输出不正确

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

首先,我要感谢所有读到这篇文章并试图帮助我解决这个问题的人,非常感谢

我正在编写一个汇编程序,用二分法计算IEEE-754格式的数字的平方根。我相信我对二分法的实现是正确的(尽管我可能会做得更有效),因为当我使用我的实现打印出一个数字的平方根,并从
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) 我需要换衣服