I need to calculate a polynomial at a certain point using the coprocessor, but I have few problems with the implementation. My program doesn't show anything and registers behave very strangely when I load power on stack, i use MASM 32 bit assembly
Example : For P(X) = 1.2 + 3X + 4.9X^3 + 8.27X^4 i will have the variables: p DD 1.2, 3, 0, 4.9, 8.27 ,n EQU ($-p)/4 -1 and the output will be the polynom in a certain point
My code:
.386
.model flat, stdcall
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;include libraries
includelib msvcrt.lib
extern exit: proc
extern printf: proc
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
public start
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.data
;p is my array of coefficients
p DD 1.2, 3, 0, 4.9, 8.27
n equ ($-p)/type p
;x is the value in which I calculate the polynomial
x dq 3.0
zero dq 0.0
doi dq 2.0
power dd 0
valoare dd 0
format DB "%lf", 0
.code
start:
;move in ecx the numbers of coefficients
mov ecx,n
;edx is the index for my array
xor edx,edx
;ebx is my array
mov ebx,offset p
FINIT ;INITIALIZARE COPROCESOR
fld zero
polinom:
;calculate x to power
fld power
FLD x ;st[0]=x, st[1]=power
FYL2X ; st[1]=st[1]*log2(st[0])
FLD1 ; st[0]=1, st[1] = FYL2X
FXCH st(1)
FSUB ST(0), ST(1); st[0]=st[0]-st[1]
F2XM1
FLD1
FADD ST(0), ST(1)
FLD doi
FMUL
;multiply it by the corresponding coefficient
FLD QWORD ptr [ebx+edx]
FMUL
add eax,4
inc power
;the value coeff* x ^ y will be in st (0) and the partial value of the polynomial will be in st(5)
;example for 3x^2+2x+1, in st(0) will be 3x^2 and in st(5) will be 2x+1
FXCH ST(1)
FXCH ST(5)
FADD
loop polinom
;FST ST[0] ;SAVE RESULT
lea edi,valoare
FST QWORD ptr[edi]
;SHOW RESULT
push dword ptr [valoare+4]
push dword ptr [valoare]
push offset format
call printf
add esp, 12
;terminarea programului
push 0
call exit
end start
You define your array of coefficients as dwords, i.e. 32-bit float
.
p DD 1.2, 3, 0, 4.9, 8.27
But then you use FLD QWORD ptr [ebx+edx]
to load a qword (64-bit double
) from it. So you're treating the bit-patterns of two adjacent float
s as one double
.
Also, you're loading the same double
every time because you never modify ebx
or edx
after setting ebx=p
and edx=0
.
Use fmul dword ptr [ebx]
/ add ebx, 4
You're also going to overflow the x87 register stack so fld
produces NaN, when st(0)
.. st(7)
are already in use. You don't seem to be popping anything ever. See https://masm32.com/masmcode/rayfil/tutorial/, and other links in https://stackoverflow.com/tags/x86/info.
Use fmulp
, faddp
, and fstp
to pop values when you're done with them.
Or fmul
with a memory operand instead of fld
+ fmulp
.
I have no idea what other bugs your code might have, but you definitely have these bugs and those both explain seeing major weirdness in FP registers while debugging.
BTW, you can use sub esp,8
/ fstp qword ptr [esp]
to store the result directly onto the call stack as an arg for printf
. You don't need valoare
.
Or better, use SSE2 mulsd
for scalar FP math, instead of x87, but apparently your assignment requires you to use x87 fyl2x
to do this in a very inefficient way, and apparently with x87.
If you weren't forced to do it the inefficient way, you could just do power *= x
to get x, x^2, x^3, ... in a loop. Building up a power one multiply at a time instead of redoing the each power separately is called a strength-reduction optimization, like turning tmp = i*10
into tmp += 10
.