Из журнала ZX Format #7, Санкт-Петербург, 06.12.1997 Быстрые вычисления в ассемблере (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,#0001 ;счетчик (на 24) и LD B,H ;трехбайтовый хранитель EXX ;результата DIV1 SLA 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' ;накопитель=делитель DIV3 EX 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 DIV2 EXX 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,#0000 ;подготовка резултата LD E,B ;коэф.текущего разряда LD D,H LD B,#08 ;счетчик MCYC SRL 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,#0000 ;результат (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 ;выход FLAG DB 0 1 в переменной FLAG в случае переполне- ния результата;хотя очень часто программы все продуманы и необходимости в нем нет. Все возможные последующие операции(сложе- ние,вычитание) с ответом такие-же,как и в делении. Если разберетесь, то мы думаем,вы без особого труда сами сможете переделать процедуры и под большее количество байт для повышения точности расчетов. Напоминаем, что процедурки для 3-х бай- товых чисел вы можете использовать как для подсчета целых чисел, так и дробных. Продолжение следует... _________________________________________