首先,我要感谢任何阅读本文并试图帮助我解决这个问题的人,非常感谢。
我正在编写一个汇编程序,以使用二分法计算 IEEE-754 格式的数字的平方根。我相信我对二分法的实现是正确的(尽管我可能可以更有效地做到这一点),因为当我使用我的实现打印出数字的平方根并打印出 FPU 给我的平方根时fsqrt
在这两种情况下,对于我尝试过的每个输入数字,我都会得到相同的结果。所以这让我相信我打印的数字不正确。我究竟做错了什么?
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
[另外:输入数字作为命令行参数传递。]
再次感谢!