5.5.4. Трансцендентные функции

Многие операции при работе с графикой используют умножение числа на синус (или косинус) некоторого угла, например при повороте: в = зіп(п) х V. При вычис­лении с фиксированной запятой 16:16 это уравнение преобразуется в в = іпг.(>іп(п) х х 65 536) х у/65 536 (где Ы - целая часть). Для требовательных ко времени работы участков программ, например для работы с графикой, значения синусов принято считывать из таблицы, содержащей результаты выражения іпфіп(п) х 65 535), где п меняется от 0 до 90 градусов с требуемым шагом (редко требуется шаг мень­ше 0,1 градуса). Затем синус любого угла от 0 до 90 градусов можно вычислить с помощью всего одного умножения и сдвига на 16 бит. Синусы и косинусы дру­гих углов вычисляются в соответствии с обычными формулами приведения:

біп(х) = зіп(18СНх) для 90 < х < 180

біп(х) = -біп(х-180) для 180 < х < 270

біп(х) = -біп(360-х) для 270 < х < 360

соб(х) = біп(90-х)

хотя часто используют таблицу синусов на все 360 градусов, устраняя дополни­тельные проверки и изменения знаков в критических участках программы.

mm

Сложные приемы

Таблицы синусов (или косинусов), используемые в программе, можно создать заранее с помощью простой программы на языке высокого уровня в виде тексто­вого файла с псевдокомандами DW и включить в текст программы директивой include. Другой способ, занимающий меньше места в тексте, но чуть больше вре­мени при запуске программы, - однократное вычисление всей таблицы. Таблицу можно вычислять как с помощью команды FPU fsin и потом преобразовывать к же­лаемому формату, так и сразу в формате с фиксированной запятой. Существует

довольно популярный алгоритм, позволяющий вычислить таблицу косинусов (или синусов, с небольшой модификацией), используя рекуррентное выражение

cos(xk) = 2cos(step)cos(xkи) - cos(xk2), где step - шаг, с которым вычисляются косинусы, например 0,1 градуса. .

liss.asm

Строит фигуры Лиссажу, используя арифметику и генерацию таблицы косинусов.

Фигуры Лиссажу - семейство кривых, задаваемых

x(t) = cos(SCALE_V х t) y(t)   = sin(SCALE_H x t)

с фиксированной запятой

параметрическими выражениями

Чтобы выбрать новую фигуру, измените параметры БСАПЕ.Н и 5СА1_Е_У,

для построения незамкнутых фигур удалите строку асй с11,512 в процедуре тоуе^роп.п1:.

 

.model

tiny

 

 

. code

 

 

 

.386

 

Будут использоваться 32-битные регистры.

 

org

lOOh ;

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

SCALE_H

equ

3 ;

Число периодов в фигуре по горизонтали.

SCALE_V

equ

5

Число периодов по вертикали.

start

proc .

near

 

 

eld

 

Для команд строковой обработки.

 

mov

di, off set cos_table

;   Адрес начала таблицы косинусов.

 

mov

ebx,16777137 ;

224 х cos(360/2048)   - заранее вычисление

 

mov

CX.2048 ;

число элементов для таблицы.

 

call

build_table ;

Построить  таблицу косинусов.

 

mov

ax,0013h ;

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

 

int

lOh ;

320x200x256.

 

mov

ax,1012h ;

Установить набор регистров палитры VGA,

 

mov

bx,70h ;

начиная с регистра 70h.

 

mov

4

; Четыре регистра.

 

mov

dx, offset palette

; Адрес таблицы цветов.

 

int

lOh

 

 

push

OAOOOh

; Сегментный адрес видеопамяти

 

pop

es

;  в ES.

main_loop:

call

display_picture

;   Изобразить точку со следом.

Вычисления с фиксирован ной запятой

start

mov

dx,5000

Х0Ґ

cx, cx

mov

ah,86h

int

15h

mov

ah,1lh

int

16h

jz

main_loop

mov

ax,0003h

int

lOh

ret

 

 

endp

;  Пауза на CX:DX микросекунд.

;, Проверить, была ли нажата клавиша.

;

Если нет

продолжить основной цикл.

Текстовый режим

80x24.

; Конец

с фиксированной запятой 8:24 = 2 х с' os (span /steps) х cos(xk,) - cos(xk

360),

Процедура buildjable. Строит таблицу косинусов в формате по рекуррентной формуле cos(xk) где span - размер области, на которой вычисляются косинусы (например, a steps - число шагов,   на которые -разбивается область. Вход:   DS:DI = адрес таблицы DS: [DI] = 224

ЕВХ = 224 х cos(span/steps)

СХ = число элементов таблицы,   которые надо вычислить Выход:   таблица размером СХ х 4 байта заполнена Модифицируются: DI.CX, EAX.EDX

Заполнить второй элемент таблицы.

Два элемента уже заполнены.

table

proc near

mov ■

dword ptr [di+4],ebx

sub

cx,2

add

di,8

mov

eax,ebx

table_loop

 

imul

ebx

shrd

eax,edx,23

sub

eax, dword ptr [di-8]

stosd

 

loop

build_table_loop

ret

 

table

endp

Умножить соз(зрап/зРерз) на соз(хк1).

Поправка из-за действий с фиксированной запятой 8:24 и умножение на 2. Вычитание соз(хк 2). Запись результата в таблицу.

; Процедура

;   Изображает точку со следом. display_picture   proc near call move_point

mov mov

call

dec

dec

bp,73h bx,3

draw_point

bp bx

Переместить точку.

Темно-серый цвет в нашей палитре. Точка, выведенная три шага назад. Изобразить ее.

72п - серый цвет в нашей палитре. Точка,   выведенная два шага назад.

Сложные приемы программирования

call

draw_point

Изобразить ее.

dec

bp

71п - светло-серый цвет в нашей палитре.

dec

bx

Точка,  выведенная один шаг назад.

call

draw_point

Изобразить ее.

dec

bp

70П - белый цвет в нашей лалитре.

dec

bx

Текущая точка.

call

draw_point

Изобразить ее.

ret

 

 

endp

Процедура draw_point. Вход: ВР - цвет

ВХ

сколько шагов назад выводилась точка

draw_point

movzx movzx

call ret draw_point

proc near

cx.byte ptr point_x[bx] dx.byte ptr point_y[bx] putpi-xel_13h

endp

Х-координата. Y-координата.

Вывод точки на

экран.

Процедура тоуе_роіпі.

Вычисляет координаты для следующей точки. Изменяет координаты точек,, выведенных раньше.

move_point

inc

and

mov ifiov

mov mov

■mov imul and shl

mov mul

mov

sub

mov

mov

imul

add

proc near word ptr time word ptr time, 2047 ; в переменной time,

; Эти две команды организуют счетчик который изменяется от 0 до 2047 (7М).

ptr point_x

ebx.dword ptr point_y dword ptr point_x[1],eax dword ptr point_y[i];ebx

di.word ptr time di,di,SCALE_H di,2047 di, 2

ax,50 '

word  ptr cos_table[di+2] ;   слово (смещение + 2) от

Считать координаты точек (по байту на ' точку) и записать их Со сдвигом 1 байт.

косинус.

and

(или время) в DI.

Умножить его на SCALE_H.

Остаток от деления на 2048, так как в таблице 4 байта на

Масштаб по горизонтали. Умножение на косинус: берется старшее косинуса,   записанного в формате 8:24.

і Фактически происходит умножение на косинус в формате 8:8.

dx.OAOOOh ;   320/2  (X центра экрана)  в формате 8:8.

dx.ax ;  Расположить центр фигуры в центре экрана

byte ptr point_x,dh        ;  и записать новую текущую точку.

di.word ptr time ; Угол (или время) в DI.

di,di,SCALE_V ' ;  Умножить его на SCALE_V.

di,512 ■  ;  Добавить 90 градусов,  чтобы заменить

;  косинус на синус. Так как у нас 2048 шагов на 360 градусов,

; 90 градусов - это 512 шагов. : di,2047 ;  Остаток от деления на 2048,

shl

том mul mov

sub

mov

ret

move_point di,2

SO

word <ptr cos_table[di+2] dx,06400h

dx, ax

byte ptr point_y,dh

так как в таблице 4 байта на косинус.

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

Умножение на косинус.

200/2  и центра экрана)   в формате 8:8.

Расположить центр фигуры в центре экрана

и записать новую текущую точку.

endp

putpixel_13h

Процедура вывода точки

на экран

DX

строка, СХ = столбец, BP = цвет,   ES = AOOOh

putpixel 13h

proc

near

 

push

di

 

 

mov

ax, dx

 

;  Номер строки.

shl

ax, 8

 

;  Умножить на 256.

mov

di, dx

 

 

shl

di, 6

 

; Умножить на 64

add

di, ax

 

;  и сложить - то же, что

add

di, cx

 

■ ;   Добавить номер столбца.

mov

ax, bp

 

 

stosb

 

 

;   Записать в видеопамять.

pop

di

 

 

ret

 

 

 

putpixel_13h

endp

 

 

и умножение на 32O.

point_x

point_y

time palette

db OFFh,OFFh, OFFh, OFFh

db OFFh,OFFh, OFFh,OFFh

db ?

dw 0

db 3Fh, 3Fh,3Fh

db 30h, 30h,30h

db ' 20h, 20h,20h

db l0h,lOh,1.Oh ; Х-координаты точки и хвоста.

; У-координаты точки и хвоста. Пустой байт - нужен для команд сдвига координат на один байт Параметр в уравнениях Лиссажу - время или

Белый.

Светло-серый.

Серый.

Темно-серый.

cos_table dd 1000000b ; Здесь начинается таблица косинусов,

end start

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