Где можно найти алгоритмы с многократным умножением и делением?
Я работаю над микроконтроллером без размножения и разделения оборудования. Мне нужно подготовить алгоритмы программного обеспечения для этих основных операций, которые являются хорошим балансом компактных размеров и эффективности. Мой порт компилятора C будет использовать эти альгоны, а не сами разработчики C.
Мой google-fu пока что вызывает шум в этой теме.
Может ли кто-нибудь указать мне что-то информативное? Я могу использовать команды add/sub и shift. Алгоритмы поиска на основе таблицы также могут работать для меня, но я немного переживаю за то, что так много перерабатываю в компилятор back-end... um, так сказать.
Ответы
Ответ 1
Здесь простой алгоритм умножения:
-
Начните с самого правого бита множителя.
-
Если бит в множителе равен 1, добавьте multipicand
-
Сдвиг мультипликатора на 1
-
Переместитесь к следующему бит в мультипликаторе и вернитесь к шагу 2.
И вот алгоритм деления:
-
Если делитель больше дивиденда, остановитесь.
-
В то время как регистр делителей меньше регистра дивидендов, сдвиг влево.
-
Регистр сдвига сдвига на 1.
-
Вычтите регистр делителей из регистра дивидендов и измените бит на 1 в реестре результатов на бит, который соответствует общему числу сдвигов, выполненных в регистре делителей.
-
Начните с шага 1 с регистром делителя в исходном состоянии.
Конечно, вам нужно поставить чек для деления на 0, но он должен работать.
Эти алгоритмы, конечно, предназначены только для целых чисел.
Ответ 2
Здесь алгоритм деления: http://www.prasannatech.net/2009/01/division-without-division-operator_24.html
Я предполагаю, что мы говорим о ints?
Если нет поддержки аппаратного обеспечения, вам придется реализовать свое собственное исключение по отдельности.
(Мне не повезло быстро найти алгоритм умножения, но я буду продолжать искать, если кто-то еще его не найдет).
Ответ 3
Один простой и довольно совершенный алгоритм умножения для целых чисел Русское крестьянское умножение.
Для рациональных действий вы можете попробовать двоичную нотацию цитат, для которой деление проще обычного.
Ответ 4
Моя любимая ссылка на такие вещи, доступные в виде книги:
http://www.hackersdelight.org/
Также вы не можете ошибиться в TAoCP: http://www-cs-faculty.stanford.edu/~uno/taocp.html
Ответ 5
Оказывается, у меня все еще есть старый код ассемблера 68000 для длительного умножения и длинного деления. Код 68000 довольно чистый и простой, поэтому его легко перевести на ваш чип.
68000 умножил и разделил инструкции IIRC - я думаю, что они были написаны как учебное упражнение.
Решил просто поместить код здесь. Добавлены комментарии и при этом исправлена проблема.
;
; Purpose : division of longword by longword to give longword
; : all values signed.
; Requires : d0.L == Value to divide
; : d1.L == Value to divide by
; Changes : d0.L == Remainder
; : d2.L == Result
; : corrupts d1, d3, d4
;
section text
ldiv: move #0,d3 ; Convert d0 -ve to +ve - d3 records original sign
tst.l d0
bpl.s lib5a
neg.l d0
not d3
lib5a: tst.l d1 ; Convert d1 -ve to +ve - d3 records result sign
bpl.s lib5b
neg.l d1
not d3
lib5b: tst.l d1 ; Detect division by zero (not really handled well)
bne.s lib3a
rts
lib3a: moveq.l #0,d2 ; Init working result d2
moveq.l #1,d4 ; Init d4
lib3b: cmp.l d0,d1 ; while d0 < d1 {
bhi.s lib3c
asl.l #1,d1 ; double d1 and d4
asl.l #1,d4
bra.s lib3b ; }
lib3c: asr.l #1,d1 ; halve d1 and d4
asr.l #1,d4
bcs.s lib3d ; stop when d4 reaches zero
cmp.l d0,d1 ; do subtraction if appropriate
bhi.s lib3c
or.l d4,d2 ; update result
sub.l d1,d0
bne.s lib3c
lib3d: ; fix the result and remainder signs
; and.l #$7fffffff,d2 ; don't know why this is here
tst d3
beq.s lib3e
neg.l d2
neg.l d0
lib3e: rts
;
; Purpose : Multiply long by long to give long
; Requires : D0.L == Input 1
; : D1.L == Input 2
; Changes : D2.L == Result
; : D3.L is corrupted
;
lmul: move #0,d3 ; d0 -ve to +ve, original sign in d3
tst.l d0
bpl.s lib4c
neg.l d0
not d3
lib4c: tst.l d1 ; d1 -ve to +ve, result sign in d3
bpl.s lib4d
neg.l d1
not d3
lib4d: moveq.l #0,d2 ; init d2 as working result
lib4a: asr.l #1,d0 ; shift d0 right
bcs.s lib4b ; if a bit fell off, update result
asl.l #1,d1 ; either way, shift left d1
tst.l d0
bne.s lib4a ; if d0 non-zero, continue
tst.l d3 ; basically done - apply sign?
beq.s lib4e ; was broken! now fixed
neg.l d2
lib4e: rts
lib4b: add.l d1,d2 ; main loop body - update result
asl.l #1,d1
bra.s lib4a
Кстати, я никогда не выяснял, нужно ли было сначала конвертировать все в позитивное. Если вы осторожны со сменными операциями, это может быть предотвращено издержки.
Ответ 6
Чтобы умножить, добавьте частичные продукты из сдвинутого множителя в аккумулятор, если соответствующий бит в множителе установлен. Множитель Shift и множитель в конце цикла, тестовый множитель и 1, чтобы увидеть, нужно ли делать добавление.
Ответ 7
Микрочипы серии Microchip PICmicro 16Fxxx не имеют инструкции умножения или деления.
Возможно, некоторые из программ мягкого размножения и мягкого разделения для него могут быть перенесены в ваш MCU.
PIC Микроконтроллер Основные методы умножения математики
PIC Микроконтроллер Основные методы математического отдела
Также проверьте "Метод Ньютона" для деления.
Я думаю, что этот метод дает наименьший исполняемый размер любого алгоритма деления, который я когда-либо видел, хотя объяснение делает его более сложным, чем оно есть на самом деле.
Я слышал, что некоторые ранние суперкомпьютеры Cray использовали метод Ньютона для деления.