Решение квадатных уравнений с помощью сопроцессора

    Доброго здоров'ячка! Сегодня я расcкажу вам как решать квадратные уравнения с помощью сопроцесcора. Но, что это такое? Я не буду вдаваться в хардверные дебри, скажу только, что наряду с обычным процессором существует, так называемый, математический сопроцессор. Его функции ясны: чтобы не забивать основной процессор всякими math кодами (некоторые он может вычислить) есть математическая машина.

Математикам: я здесь покажу как программируется сопроцессор на основе решения квадратных уравнений.

Итак приступим!

Алгоритм решения:
  1. Мы имеем формулу общего квадратного уравнения (вспоминайте школу, класс этак восьмой :-). Она выглядит так: ax^2+bx+c=0
  2. Требуется найти ее дискриминант: D=b^2-4ac
  3. Если D<0 то корней не существует, иначе п.4
  4. Если D=0 то есть один корень: X=-b/2a, иначе п.5
  5. Если D>0 то существуют два корня: X1=(-b-sqrt(D))/2a, X2=(-b+sqrt(D))/2a

    С чего же начать? Ответ прост: с очистки математической машины. Почти все программы оставляют свои коды в сопроцессоре (для краткости будем называть его СП). Делается это одной коммандой: finit

Далее, найдем дискриминант:

fld    b
; Введем в стек СП число b
fmul    b   
; Умножим b на самого себя (b^2)
fld    a
; Введем в стек СП число a
fld    temp
; Введем в стек СП число temp (temp=4)
fmul
; Умножим a на temp
fld    c
; Введем в стек СП число c
fmul
; Умножим a*temp на c (4ac)
fsubp    st(1),st(0)
; Вычтем 4ac из b^2
fst    D
; "Вытолкнем" дискриминант в переменную D

    Ну вот, D нашли. Теперь нужно его сравнить с нулем. Вот тут то и начинаются проблемы: у СП есть момент сравнивания и все, а мне нужно перейти на определенные "полки" программы. Зато у основного процессора (далее ОП) такая возможность есть, а значит, мне нужно перенести определенные флаги СП в ОП. Делается это так:

ftst
; Сравниваем D с нулем (на этом дело СП заканчивается)
fstsw    ax
; "копируем" регистр состояния SWR в регистр AX
sahf
; "копируем" флаги C0, C2, C3 (нет, я не ошибся :-) в младший байт регистра EFLAGS/FLAGS

Теперь мы можем "попрыгать" по программе, но сначала таблица соответсвий:

Условие
Команда "прыжка"
<
jc
=
jz

    Условие "больше" нам не потребуется и вы поймете почему. Я приведу и детально прокомментирую остальную часть программы, потому-что ее, фактически, нельзя разрывать:

jc    j1
; если D < 0 то goto j1
jz    j2
; если D = 0 то goto j2
; а если D > 0 то [далее]
finit
; опять очистили СП
fld    temp2
; Введем в стек СП число temp2 (temp2=2)
fmul    a
; Умножили temp2 на a
fld    D
; Введем в стек СП дискриминант
fsqrt
; Посчитали корень даскриминанта
fld    b
; Введем в стек СП число b
fchs
; Изменили знак у b
fsave    temp2[4]
; Сохранили полное (регитры и стек) состояние СП (и стерли оное)
frstor    temp2[4]
; Загрузили полное состояние
fsubr
; вычли корень дискриминанта из -b
fdivr
; первый корень
frstor    temp2[4]
; Загрузили еще раз полное состояние
fadd
; сложили корень дискриминанта и -b
fdivr 
; второй корень
jmp    ex
; "прыгнули" на "выход"
; D < 0
; !no roots!
j1:   
mov    ah,    09h
mov    dx,    offset mes1
int    21h
; вывели сообщение, что нет корней (под Win32)
jmp    ex
; "прыгнули" на "выход"
; D = 0
; X = -b/(2*a)
j2:   
finit
; опять очистили СП
fld    temp2
; Введем в стек СП число temp2 (temp2=2)
fmul    a
; Умножили temp2 на a
fld    b
; Введем в стек СП число b
fdivr
; Разделили b на 2a
fchs
; Сменили знак
; Вот и единственный корень

    Вот и все! Ошибок я не нашел (может Вы найдете). Можете вводить целые и дробные параметры - все равно получите правильный результат. Если у вас есть TASM (и за мелкими изменениями MASM) то можете скачать данную программу.

При написании я частично пользовался книгой Юрова ASSEMBLER 2-е издание, за что ему большое спасибо!

Ну вот и все, что я хотел вам сказать. Бувайте!

НАЗАД


Приложение 1. Полная программа на ASM

; <<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>
; Anton (Liloi) Moskalenko
; e-mail: liloi@mail.ru
; <<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>

; Create time & date: 15:55 14.08.2006
 
; Note: kv. urav

; Compiled with TASM 4.1

.286
.model    small
.data

    a    dd    2.0
    b    dd    4.0
    c    dd    2.0
    D    dd    ?

    mes1    db    'No roots! $'

    temp    dd    4.0
    temp2    dd    2.0

.stack    256h
.code

;Main PROC
main    proc

    push    @data
    pop    ds

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    finit

; discriminante
; C++:
; D = sqr(b)-4*a*c

    fld    b
    fmul    b   
    fld    a
    fld    temp

    fmul
    fld    c
    fmul
    fsubp    st(1),st(0)
    fst    D
   
; <=>
    ftst

    fstsw    ax
    sahf

    jc    j1
    jz    j2

; D > 0
; X1 = (-b-sqrt(D))/(2*a)
; X2 = (-b+sqrt(D))/(2*a)

    finit
   
    fld    temp2
    fmul    a
    fld    D
    fsqrt
    fld    b
    fchs

    fsave    temp2[4]
    frstor    temp2[4]

    fsubr
    fdivr    ; first root
   
    frstor    temp2[4]

    fadd
    fdivr    ; second root

    jmp    ex

; D < 0
; !no roots!

j1:    mov    ah,    09h
    mov    dx,    offset mes1
    int    21h
    jmp    ex

; D = 0
; X = -b/(2*a)

j2:    finit
    fld    temp2
    fmul    a
    fld    b
    fdivr
    fchs    ; root
   

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ex:    mov    ax,    04C00h
    int    21h

main    endp
;end of main

end    main

Приложение 2. Аналогичная программа на С++

#include <iostream.h>
#include <math.h>

int main(int argc, char *argv[])
{
    const float a = 3, b = 2, c = -1;
    float D = 0, x, x1, x2;
   
    D = pow(b,2)-4*a*c;
   
    if(D<0)
    {
        cout << "No roots!" << endl;
    }else
    if(D==0)
    {
        x = ((-1)*b)/(2*a);
    }else
    {
        x1 = ((-1)*b-sqrt(D))/(2*a);
        x2 = ((-1)*b+sqrt(D))/(2*a);
    }
   
    return 0;
}

НАЗАД
Hosted by uCoz