assemblymasm32-bit

calculate polynom value assembly 32 bit


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

Solution

  • 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 floats 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.