Программистам - Алгоритмы работы и примеры процедур для быстрых вычислений на асемблере: Умножение и деление 3-х байтовых чисел,

ZX Format #07
Быстрые вычисления в ассемблере

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-х бай-
товых  чисел  вы  можете использовать как
для подсчета целых чисел, так и дробных.

Продолжение следует.