5.6. Вычисления с плавающей запятой

Набор команд для работы с плавающей запятой в процессорах Intel достаточно разнообразен, чтобы реализовывать весьма сложные алгоритмы, и прост в исполь­зовании. Единственное, что может представлять определенную сложность, - почт■BII       Сложные приемы программирования

все команды FPU по умолчанию работают с его регистрами данных как со стеком, .выполняя операции над числами в ST(0) и ST(1) и помещая результат в ST(0), так что естественной формой записи математических выражений для FPU оказыва­ется обратная польская нотация (RPN). Эта форма ..аписи встречается в програм­мируемых калькуляторах, языке Форт и почти всегда неявно присутствует во всех алгоритмах анализа математических выражений: они сначала преобразовывают обычные выражения в обратные и только потом начинают их анализ. В обратной польской нотации все операторы указываются после своих аргументов, так что sin(x) превращается в х sin, a a + b превращается в a b +. При этом полностью про­падает необходимость использовать скобки, например: выражение (а + b) х 7 - d записывается как a b + 7 х d

Посмотрим, как выражение, записанное в RPN, на примере процедуры вычис­ления арксинуса легко с помощью команд FPU.

asin

Вычисляет арксинус по формуле asin(x) (в RPN: х х * х х * 1

Результат возвращается asm

числа,   находящегося в st(0)   (-1 < х < +1), = atan(sqrt(x2/(1-x2)))

/ sqrt atan). ■

st(0),   в стеке FPU должно быть два свободных регистра.

ргос

rear

Комментарий показывает содержимое стека FPU:. Первое выражение - ST(0),   второе - ST(1) и т. д. x (начальное состояние стека)

fid

st(0)

x, х

fmul

 

X2

fid

st(0)

х2, х2

fld1

 

1, х2, х2

fsubr

 

1-х:2, х2

fdiv

 

xV(1-x2)

fsqrt

 

8!|rt(x2/(1-Xz))

fldl

 

1, sqrt(x2/(1-x2))

fpatan

 

atan(sqrt(x2/(1-x2)))

ret

 

 

endp

 

 

аэФп

Теперь попробуем решить небольшое дифференциальное уравнение ние Ван-дер-Поля для релаксационных колебаний:

х" = -х +■ т(1-х2)х', т > О

будем двигаться по времени с малым шагом 1г, так что

уравне-

x(t + h) x(t + h)'

или, сделав замену у =

x(t) + hx(t)' : x(t)' + hx(t)"

У = х =

У

x + hy х)

Решение этого уравнения для всех т > 0 оказывается периодическим аттрак­тором, поэтому, если из-за ошибок округления решение отклоняется от истинногов любую сторону, оно тут же возвращается обратно. При т - 0, наоборот, решение оказывается неустойчивым и ошибки округления приводят к очень быстрому росту х и у до максимально допустимых значений для вещественных чисел.

Эту программу нельзя реализовать в целых числах или числах с фиксирован­ной запятой, потому что значения хих' различаются на много порядков - кривая содержит почти вертикальные участки, особенно при больших т.

усір.азт

Решение уравнения Ван-дер-Поля Х(Т)' ' = -х(с) + т(1-х(г)2)х(і)'

с т = О, 1, 2, 3, 4, 5, 6, 7, 8.

Программа выводит на экран решение

Esc

выход,  любая другая клавиша

с m = 1, нажатие клавиш 0-8 изменяет - пауза до нажатия одной из Esc, 0-8.

т.

start

m = ■ again:

_key: mov

int

cmp

U

cmp

cmp ja

sub

tiny

.286

;

Для команд         и рора.

.287

;

Для команд FPU.

.code

 

 

org

100h           ' ;

СОМ-программа.

proc

near

 

eld

 

 

push

OAOOOh

 

pop

es                 ■ ;

Адрес видеопамяти в ES.

mov

ax,0012h

 

int

10h ;

Графический   режим 640x480x16.

finit

 

Инициализировать FPU.

xor

si, si

будет содержать координату t и меняться

 

I

от 0 до 640.

fld1

J

1

fild

word ptr

32, 1

fdiv

 

h                  (h = 1/hinv)

новка начальных значений для

_display:

1, х =

h = 1/32, у = =

 

fild word ptr m

m, h

fid

st(1)

x, m, h       (x = h)

fldz

 

: У, x, m, h      (y = 0)

call

_display

Выводить на экран решение, пока

ah, lOh

16h

al,1Bh

g_out al, '0' g_key al,'8' g_key al,'0'

не будет нажата клавиша. Чтение клавиши с ожиданием. Код нажатой клавиши 'в AL. Если это Esc, выйти из программы. Если код меньше "О", пауза/ожидание следующей клавиши. Если  код больше "8", пауза/ожидание следующей клавиши. Иначе:  AL = введенная цифра,

fstp

fstp fstp byte ptr

st(0) st(0) st(0)

jmp short again

g_out:

start mov int

ret endp ax,0003h 10h

m = введенная x,, m, lp m, h h

Текстовый режим. Конец программы.

Процедура Сівр1ау_. Пока не нажата клавиша, 640 точек.

выводит решение на экран,   делая паузу после каждой -из

.display dismore:

mov mov shr mov

sub

call

call

mov

mov

sub

call

inc

inc cmp

jl

sub

not_endscreen:

mov xor mov

int

mov

int

jz

ret

.display proc

near

bx,0 cx,si

CX,1

dx,240

ptr

putpixellb

next_x

bx,l

dx,240

ptr

putpixellb

si

si

si,640*2

not_endscreen si,640*2

dx,5000 •,

cx, cx ah,86h

15h

ah,11h

16h

dismore endp

Процедура пехг_х.

Проводит вычисления по формулам:

у = у + Ь(т(1-хЛ2)у-х)

х = х + Ьу

Вход: = у, бЬ(1) = х, вЬ(2) = Выход:       = у,   бЬ(1)  = х,   вЬ(2) =

Стереть предыдущую точку: цвет = СХ - строка. РХ - столбец.

Вычислить х(г) для следующего г. Вывести точку:  цвет = 1.

0.

DX

столбец.

81 = 81 + 2 (массив слов).

Если 81 достигло  конца массива IX,

пропустить паузу.

Переставить 81 на начало массива IX.

Пауза на СХ:РХ микросекунд.

Проверить,  была ли нажата 'клавиша. Если нет - продолжить вывод на экран. Иначе - закончить процедуру.

m, m, st(3)

st(3) = = h.

h, x 100 віммі

237

next„x proc      rear ■

fldl ; 1, y, x, m, h

fid st (2)       ■ ; x,  1, y, x, m, h

fmul st,st(3) ; x2,  1, y, x, m, h

fsub : (1-х2), у, x, m, h

fid st(3) ; m,  (1-х2), y, x, m, h

fmul ; M, y, x, m, h (M = m(1-x2))

fid st(l) ; у, M, y, x, m, h

fmul ; My, y, x, m,' h

fid st(2) ; x, My, y, x, m, h

fsub ; My-x, y, x, m, h

fid st(4) ; h, My-x, y, x, m, h

fmul ; h(My-x), y, x, m, h

fid st(l) ; y, h(My-x), y, x, m, h

fadd ; Y, y, x, m, h (Y = у + h(My-x))

fxch ; y, Y, x, m, h

fid st(4) ' ; h, y, Y, x, m, h

fmul ; yh, Y, x, m, h

faddp st(2),st ; Y, X, m, h (X = x + hy)

fid st(1) ; X, Y, X, m, h

fild word ptr c_100    ; 100, X, Y, X, m, h

fmul ; 100X, Y, X, m,-h

fistp word ptr ix[si]  ; Y, X, m, h

ret

next x endp

Процедура вывода точки на экран в режиме,  использующем 1 бит на пиксел.

; DX = строка, CX = столбец, ES = AOOOh,  ВХ = цвет (1 - белый,  0 - черный).

Все регистры сохраняются.

putpixellb proc near

pusha ; Сохранить регистры.

push bx

xor bx,bx

mov ax.dx ; AX = номер строки.

irnul ax,ax, 80 ; AX = номер строки x число байтов в строке,

push сх

shr cx,3 ; CX = номер байта в строке,

add ах,сх   ■ ; АХ = номер байта в видеопамяти,

mov dl.ax ; Поместить его в DI и SI.

mov si,di

pop сх' ; CX снова содержит номер столбца.'

mov bx,0080h

and cx,07h ; Последние три бита СХ =

; остаток от деления на 8 =

номер бита в байте, считая справа налево.

shr bx.cl ; Теперв нужный бит в BL установлен в 1.

lods es:byte ptr ix    ; AL = байт из видеопамяти.

pop dx

dec dx Проверить цвет.


 

 

 

 

 

 

is

black

 

; Если 1 - ' :

 

or

ax, bx

 

; установить выводимый бит в 1.

 

jmp

short

white

 

black:

not

bx

 

; Если 0 -

 

and

ax, bx

 

: установитв выводимый цвет е 0

white:

 

 

 

 

 

stosb

 

 

; и вернуть байт на место.

 

popa

 

 

; Восстановить регистры.

 

ret

 

 

; Конец.

putpixellb

'endp

 

 

m

 

dw

1

: Начальное значение т.

с 100

 

dw

100

: Масштаб по вертикали.

hinv

 

dw

32

; Началвное значение 1/Ь.

ix:

 

 

 

; Начало буфера для  значений х(Ю

 

 

 

 

;   (всего 1280 байт за концом программы) .

 

end

start