рассчитать полином значение сборки 32 бит - PullRequest
0 голосов
/ 06 мая 2018

Мне нужно вычислить полином в определенной точке, используя сопроцессор, но у меня мало проблем с реализацией. Моя программа ничего не показывает и регистры ведут себя очень странно, когда я загружаю питание в стеке, я использую 32-битную сборку MASM

Пример: Для P (X) = 1,2 + 3X + 4,9X ^ 3 + 8,27X ^ 4 у меня будут переменные: p DD 1,2, 3, 0, 4,9, 8,27, n EQU ($ -p) / 4 -1 и на выходе будет полином в определенной точке

Мой код:

    .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

1 Ответ

0 голосов
/ 06 мая 2018

Вы определяете свой массив коэффициентов как двойные слова, то есть 32-битный float.

p DD 1.2, 3, 0, 4.9, 8.27

Но затем вы используете FLD QWORD ptr [ebx+edx] для загрузки из него qword (64-битный double). Таким образом, вы рассматриваете битовые комбинации двух соседних float s как один double.

Кроме того, вы загружаете один и тот же double каждый раз, потому что вы никогда не изменяете ebx или edx после установки ebx=p и edx=0.

Использование fmul dword ptr [ebx] / add ebx, 4


Вы также переполните стек регистров x87, поэтому fld выдает NaN , когда st(0) .. st(7) уже используется. Похоже, ты никогда ничего не пишешь. См. http://www.ray.masmcode.com/tutorial/index.html, и другие ссылки в https://stackoverflow.com/tags/x86/info.

Используйте fmulp, faddp и fstp, чтобы вытолкнуть значения, когда вы закончите с ними. Или fmul с операндом памяти вместо fld + fmulp.

Я понятия не имею, какие еще ошибки могут быть в вашем коде, но у вас определенно есть эти ошибки, и они оба объясняют, что во время отладки наблюдаются серьезные странности в регистрах FP.


Кстати, вы можете использовать sub esp,8 / fstp qword ptr [esp] для сохранения результата непосредственно в стек вызовов в качестве аргумента для printf. Вам не нужно valoare.


Или лучше, используйте SSE2 mulsd для скалярной математики FP вместо x87, но, очевидно, ваше назначение требует, чтобы вы использовали x87 fyl2x, чтобы сделать это очень неэффективно, и, очевидно, с x87.

Если вы не были вынуждены сделать это неэффективным способом, вы можете просто сделать power *= x, чтобы получить x, x ^ 2, x ^ 3, ... в цикле. Наращивание мощности по одному умножению за раз вместо того, чтобы переделывать каждую отдельную мощность, называется оптимизацией снижения прочности, подобно превращению tmp = i*10 в tmp += 10.

...