Assembly 使用FPU Nasm x86程序集进行计算时获取-nan

Assembly 使用FPU Nasm x86程序集进行计算时获取-nan,assembly,x86,nasm,nan,x87,Assembly,X86,Nasm,Nan,X87,首先我要感谢任何回复此邮件的人,非常感谢您的帮助 我试图计算作为命令行参数传递给程序的一组浮点数的标准偏差。首先,我将每个参数字符串存储在一个临时变量中,然后使用sscanf将它们解析为浮点数。我的第一个问题是第一个,当我说第一个的时候,我说的是在我的程序名后面的那个…所以实际上第二个命令行参数没有被解析。在我用来计算数字平均值的循环中,我尝试在将每个参数解析为浮点数后立即打印出来。它总是打印除第一张外的所有照片。第一个总是打印为-nan。此外,变量std_dev也会打印为-nan,尽管我从未修

首先我要感谢任何回复此邮件的人,非常感谢您的帮助

我试图计算作为命令行参数传递给程序的一组浮点数的标准偏差。首先,我将每个参数字符串存储在一个临时变量中,然后使用sscanf将它们解析为浮点数。我的第一个问题是第一个,当我说第一个的时候,我说的是在我的程序名后面的那个…所以实际上第二个命令行参数没有被解析。在我用来计算数字平均值的循环中,我尝试在将每个参数解析为浮点数后立即打印出来。它总是打印除第一张外的所有照片。第一个总是打印为-nan。此外,变量std_dev也会打印为-nan,尽管我从未修改过它。这让我困惑。我做错了什么

代码如下:

EXTERN printf
EXTERN sscanf 
GLOBAL main

SEGMENT .data
form0:      DB "The standard deviation is: %d", 10, 0
form1:      DB "The standard deviation is: %f", 10, 0 
fpform:     DB "%f", 0  
avg:        DD 0.0 
std_dev:    DD 0.0   
temp:       DD 0.0 

debugform:  DB "temp=%f, std_dev=%f, avg=%f", 10, 0 

SEGMENT .text 
main:
        push    ebp                         ; compose stack frame 
        mov     ebp, esp
        push    ebx
        push    ecx

        mov     ebx, [ebp + 8]              ; ebx = # of params
        mov     ecx, [ebp + 12]             ; ecx = &param_table 
        cmp     ebx, dword 1                ; no params passed? 
        je      .end_0                      ; YES - print 0 
                                            ; NO - compute and print std_dev 
        finit                               ; initialize fpu 
        fldz                                ; initialize fpu registers with 0's 
        fldz
        fldz
        fldz
        fldz
        fldz
        fldz
        fldz

        call    findStdDev                  ; find the standard deviation of the numbers passed as command line params
        call    debugPrint
        pushad                              ; preserve all registers before making system call
        fld     dword [avg]                 ; load standard deviation into fpu
        sub     esp, 8                      ; reserve space for a qword in the stack
        fstp    qword [esp]                 ; load the 64-bit representation of std_dev into stack
        push    form1                       ; pass format string
        call    printf                      ; print out the standard deviation
        add     esp, 12 
        popad 

        jmp     .end                        ; 
        pop     ebp 
        ret 
.end_0:                                     ; if no parameters are passed, print std_dev = 0
        push    dword 0 
        push    form0
        call    printf
        add     esp, 8
.end: 
        pop     ecx
        pop     ebx
        pop     ebp                         ; restore used register and return from program 
        ret 

;-----------------------------------------------------------------------------------
findStdDev:                                 ; assumes ebx = # params, ecx = &param_table 
        push    edi                         ; save used regs 
        push    esi                         
        xor     esi, esi                    ; clear esi as a precaution 
        mov     esi, dword 1                ; loop counter for loop to find average of numbers  
.find_avg:  
        cmp     esi, ebx                    ; esi == number of params?
        je      ._break                     ; YES - break 
        pushad                              ; preserve registers before calling a C function
        push    temp                        ; temp storage for string representation of input nums
        push    fpform                      ; format string 
        push    dword [ecx + esi*4]         ; current command line param
        call    sscanf                      ; parse string to f.p. 
        add     esp, 12 
        popad 

        call    debugPrint                  ; should leave the CPU and FPU registers how they were before the call

        fld     dword [temp]                ; st0 = temp ; st1 = sum 
        faddp   st1, st0                    ; st0 = sum + temp
        ;call   debugPrint                  ; should leave the CPU and FPU registers how they were before the call
        inc     esi                         ; move to next command line param
        jmp     .find_avg

._break:
        mov     [temp], ebx                 ; temp = num of params
        sub     [temp], dword 1
        fld     dword [temp]                ; st0 = #params; st1 = sum of params
        fdivp   st1, st0                    ; st0 = (sum of params)/(#params)
        fstp    dword [avg]                 ; set avg; clear st0 

        pop     esi 
        pop     edi 
        ret 

;----------------------------------------------------------------------------------------       
debugPrint:

        pushfd 
        pushad
        sub     esp, 24
        fld     dword [avg]
        fld     dword [std_dev]
        fld     dword [temp]
        fstp    qword [esp]
        fstp    qword [esp+8]
        fstp    qword [esp+16]
        push    debugform
        call    printf
        add     esp, 28
        popad
        popfd
        ret 
再次感谢


[编辑:我还没有完成标准偏差的实际计算。我只有一个计算平均值的循环。]

我对FPU不是很有经验,但我认为fldz的字符串是一个错误。此时,您的FPU已满,无法容纳其他号码,不是吗?谷歌只是简单的FPU教程。这实际上是很有意义的。我只调用fldz一次,这就固定了我的输出。也就是说,当我在find_avg循环中调用debugPrint时,在每个迭代中,temp都有当前迭代的命令行参数,并且avg和std_dev都是0,正如预期的那样。非常感谢。但是,当我除以参数的数量时,仍然存在一个问题。在子标签中,当我fld dword[temp]时,temp包含0,无论出于何种原因。所以当我尝试除法时,我得到了inf,这是被0除法时应该发生的事情,但我不明白为什么temp仍然是0。在你的.\u break标签上,你把一个整数argc放入[temp]。我想你应该把它当作fild,而不是fld。我想那也行。我所做的,我知道是非常复杂的,只是使用参数的数量作为循环的计数器,在循环中,我反复将1加载到st0中,然后将其添加到st1中的运行总数中,直到得到参数的总数,然后使用fstp将该和加载到我创建的另一个变量numVars中。谢谢你的帮助!