Листинг 15.2

;********

;div32x8» — 32/8 деление беззнаковых чисел

;Делимое и результат в count_HH (старший), countTH,

;countTM, countTL (младший)

;делитель в cikle

;требуется четыре временных регистра dremL — dremHH

;из диапазона r16-r31

;для хранения остатка

;********

div32x8:

        clr dremL  ;clear remainder Low byte

        clr dremM  ;clear remainder

        clr dremH  ;clear remainder

        sub dremHH,dremHH  ;clear remainder High byte and carry

        ldi cnt,33  ;init loop counter

d_1:  rol countTL  ;shift left dividend

        rol countTM

        rol countTH

        rol count_HH

        dec cnt  ;decrement counter

        brne d_2  ;if done

        ret  ;return

d_2:  rol dremL  ;shift dividend into remainder

        rol dremM

        rol dremH

        rol dremHH

        sub dremL,cikle  ;remainder = remainder — divisor

        sbci dremM,0

        sbci dremH,0

        sbci dremHH,0

        brcc d_3  ;if result negative

        add dremL,cikle  ;restore remainder

        clr temp

        adc dremM,temp

        adc dremH,temp

        adc dremHH,temp

       clc  ;clear carry to be shifted into result

       rjmp d_1  ;else

d_3: sec  ;set carry to be shifted into result rjmp d_1

;******** конец 32x8

Многие подобные задачи на деление удается решить значительно более простым и менее громоздким методом, если заранее подгадать так, чтобы делитель оказался кратным степени двойки. Тогда все деление сводится, как мы знаем, к сдвигу разрядов вправо столько раз, какова степень двойки. Для примера предположим, что мы некую величину измерили 64 раза, и хотим узнать среднее. Пусть сумма укладывается в 2 байта, тогда вся процедура деления будет такой:

;деление на 64

       clr count_data  ;счетчик до 6

div64L:

       lsr dataH  ;сдвинули старший

       ror dataL  ;сдвинули младший с переносом

       inc count_data

       cpi count_data,6

       brne div64L

He правда ли, гораздо изящнее и понятнее? Попробуем от радости решить задачку, которая на первый взгляд требует, по крайней мере, знания высшей алгебры — умножить некое число на дробный коэффициент (вещественное число с «плавающей запятой»). Теоретически для этого требуется представить исходные числа в виде «мантисса — порядок», сложить порядки и перемножить мантиссы (см. [10]). Нам же неохота возиться с этим представлением, т. к. мы не проектируем универсальный компьютер, и в подавляющем большинстве реальных задач все конечные результаты у нас представляют собой целые числа.

На самом деле эта задача решается очень просто, если ее свести к последовательному умножению и делению целых чисел, представив реальное число в виде целой дроби с оговоренной точностью. Например, число 0,48576 можно представить как 48 576/100 000. И если нам требуется на такой коэффициент умножить, к примеру, результат какого-то измерения, равный 976, то тогда можно действовать, не выходя за рамки диапазона целых чисел: сначала умножить 976 на 48 576 (получится заведомо целое число 47 410 176), а потом поделить результат на 105, чисто механически перенеся запятую на пять разрядов. Получится 474,10176 или, если отбросить дробную часть, 474. Большая точность нам и не требуется, т. к. и исходное число было трехразрядным.

Улавливаете, к чему я клоню? С числами в десятичном виде хорошо работать руками, просто отсчитывая разряды. Нам же делить на сто тысяч в 8-разрядном МК крайне неудобно — представляете, насколько громоздкая процедура получится? Наше ноу-хау будет состоять в том, что мы для того, чтобы «вогнать» дробное число в целый диапазон, будем использовать не десятичную дробь, а двоичную — деление тогда сведется к описанной «механической» процедуре сдвига, аналогичной переносу запятой в десятичном виде.

Перейти на страницу:

Поиск

Похожие книги