Быстрые вычисления в ассемблере
music by COOPER
(C) GreenFort
_
Да, сколько проблем с этой математи-
кой, а ведь надо, и надо просто повсе-
местно. То векторная графика дает о себе
знать, то подсчет очков в своей игрушке,
а то и расчет положения светил на небос-
воде. Так или иначе, всегда возникают си-
туации, когда скорости ПЗУшного калькуля-
тора явно недостаточно.
Мы предлагаем вашему вниманию цикл ста-
тей, посвященных математическим операци-
ям. Подразумевается, что человек читающий
эти строки уже усвоил азы программирова-
ния на Ассемблере.
Начнем с простого:
1. ДЕЛЕНИЕ.
Принцип работы процедуры деления основан
на делении в столбик, единственное отли-
чие только в системе счисления: она дво-
ичная.
1.1 Пример_простейшей_процедуры_деления:
НА ВХОДЕ : C = Делимое, В = Делитель
НА ВЫХОДЕ: L = результат, A = остаток
;L=C/B:
DIVIS XOR A ;обнуление текущего ос-
;татка
DIVIS2 LD L,#01 ;счетчик (сдвиг 8 раз)
D1 RL C ;чтение текущего разряда
RLA ;накопитель разрядов
CP B ;какой результат текущего
;разряда
JR C,ZER ;переход,если текущий
;разряд=0
SUB B ;тек.разряд=1,снятие с
;накопителя
SLI L ;занесение разряда=1
JR NC,D1 ;переход,если счетчик не
;переполнился
RET ;выход
ZER SLA L ;занесение разряда=0
JR NC,D1 ;переход,если счетчик не
;переполнился
RET ;выход
L - используется как счетчик и хранит
результат.
A - остаток деления, из C последова-
тельно считываются разряды в регистр A.
B - остается неизменным после деления.
Процедурку можно, кстати, раскрыть.
Если вам нужна большая точность деле-
ния,то можно продолжить делить.
Пример:
LD C,что делить будете
LD B,на что делить будете
CALL DIVIS;первичное деление
;C=0,A-остаток
LD H,L ;сохранение результата
CALL DIVIS2 ;вторичное деление
;без обнуления остатка
езультат в HL:
H = целая часть результата
L = дробная часть результата
Получаемая точность: +-(1/256),т.е. два
знака после запятой обеспечивается.
1.2 Процедурка_деления_3-х_байтовых_чисел
На входе : A,H,L - три байта делимого
B,D,E - три байта делителя
На выходе: A,H,L - результат
;A,H,L=(A,H,L)/(B,D,E)
DIVISIO
LD C,A ;старший байт делимого
;храним в C
XOR A ;обнуление накопителя
EXX ;резрядов
LD HL,#01 ;счетчик (на 24) и
LD B,H ;трехбайтовый хранитель
EXX ;результата
DIV1SLA L ;выборка разряда
RL H
RL C
RLA
CP B ;накопитель больше
;делителя?
JR C,DIV2 ;если меньше,то резуль-
;тат 0)
JR NZ,DIV3;в случае,если больше
; результат=1 накопитель уменьшается
EX AF,AF' ;сохранение A
LD A,C ;аналогично проверка
CP D ;младших двух байт на-
JR C,DIV22;копителя и делителя
JR NZ,DIV32
LD A,H
CP E
JR C,DIV22
DIV32 EX AF,AF' ;накопитель=делитель
DIV3EX AF,AF'
LD A,L ;накопитель-делитель
LD L,H ;(младшие 2 разряда)
LD H,C
AND A
SBC HL,DE
LD C,H
LD H,L
LD L,A
JR NC,DIV33
EX AF,AF' ;накопитель-делитель
SUB B ;старший разряд при
DEC A ;переполнении младших
DIV34 EXX ;занесение врезультат
SLI L ;текущий бит=1
RL H
RL B
EXX
JP NC,DIV1;счетчик еще не кон-
;чился
JP DIVEXIT;счетчик переполнился
;конец деления
DIV22 EX AF,AF' ;занесение в результат=0
DIV2EXX
SLA L
RL H
RL B
EXX
JP NC,DIV1;счетчик еще не кон-
;чился
DIVEXIT EXX ;счетчик переполнился
PUSH HL ;конец деления
LD A,B
EXX
POP HL
RET
DIV33 EX AF,AF' ;накопитель-делитель
SUB B ;старший разряд без
JP DIV34 ;переполнения младших
Затем довольно удобно использовать ре-
зультат для сложения или вычитания:
Сложение результата с 3-х байтовым числом
.
CALL DIVISIO
LD B,1-й байт, который прибавляем
LD DE,2 и 3 байт, которые прибавляем
ADD HL,DE
ADC A,B
.
2. УМНОЖЕНИЕ.
Умножение, как и деление базируется на
умножении в столбик.
2.1 Простейшая_процедурка_умножения.
Пример:
;HL=B*C
LD HL,#0 ;подготовка резултата
LD E,B ;коэф.текущего разряда
LD D,H
LD B,#08 ;счетчик
MCYCSRL C ;выборка разряда второ-
;го множителя
JP NC,NOADD ;разряд=0 (DE*0=0)
ADD HL,DE ;разряд=1 (DE*1=DE)
NOADD SLA E ;смена коэффициента раз-
RL D ;ряда на след. разряд
DJNZ MCYC ;цикл на 8
RET ;выход
Конечно, сразу бросается в глаза, что и
эту конструкцию можно раскрыть.
2.2 Умножение_3-х_байтовых_чисел.
;A,H,L=A,H,L*B,D,E
MULTI EXX
LD HL,FLAG;сброс переноса
RES 0,(HL)
LD B,24 ;счетчик
LD HL,#0 ;результат (C,H,L)
LD C,H
PF2 EXX
SRL B ;выборка разряда
RR D ;второго множителя
RR E
JR NC,PF3 ;разряд=0,переход на
;выборку следующего разряда
EX AF,AF' ;сложение ответа с
PUSH HL ;текущим коэф.разряда
EXX
POP DE
ADD HL,DE
ADC A,C
JP NC,NOFLAG
;результат не помещается в трех байтах!
LD A,(FLAG) ;обработчик переполне-
OR 1 ;ния
LD (FLAG),A
RET
NOFLAG LD C,A
EXX
EX AF,AF'
-PF3 SLA L ;переход к следующему
RL H ;текущий коэф.(AHL*2)
RLA
EXX
DJNZ PF2 ;цикл на 24
LD A,C
RET ;выход
FLAGDB 0
1 в переменной FLAG в случае переполне-
ния результата;хотя очень часто программы
все продуманы и необходимости в нем нет.
Все возможные последующие операции(сложе-
ние,вычитание) с ответом такие-же,как и в
делении.
Если разберетесь, то мы думаем,вы без
особого труда сами сможете переделать
процедуры и под большее количество байт
для повышения точности расчетов.
Напоминаем, что процедурки для 3-х бай-
товых чисел вы можете использовать как
для подсчета целых чисел, так и дробных.
Продолжение следует.