我正在使用没有硬件乘除器的微控制器。我需要编写这些基本操作的软件算法,以便在紧凑和高效之间取得良好平衡。我的C编译器端口将采用这些算法,而不是由C开发人员自己编写。
目前我的谷歌搜索结果大多噪音干扰。
有人能向我指出一些有用信息吗?我可以使用加/减和移位指令。基于查找表的算法也可能适合我,但我有些担心将其全部压缩进编译器的后端...恕我直言。
我正在使用没有硬件乘除器的微控制器。我需要编写这些基本操作的软件算法,以便在紧凑和高效之间取得良好平衡。我的C编译器端口将采用这些算法,而不是由C开发人员自己编写。
目前我的谷歌搜索结果大多噪音干扰。
有人能向我指出一些有用信息吗?我可以使用加/减和移位指令。基于查找表的算法也可能适合我,但我有些担心将其全部压缩进编译器的后端...恕我直言。
以下是关于IT技术的参考资料,我最喜欢的书籍:
http://www.hackersdelight.org/
此外,《计算机程序设计艺术》也是不错的选择:http://www-cs-faculty.stanford.edu/~uno/taocp.html
事实证明,我仍然有一些旧的68000汇编代码用于长乘法和长除法。 68000代码非常干净简单,因此应该很容易为您的芯片进行翻译。
如果我没记错的话,68000有乘法和除法指令-我认为这些是作为学习练习编写的。
决定将代码放在这里。添加了注释,并在此过程中解决了一个问题。
;
; 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
Microchip的PICmicro 16Fxxx系列芯片没有乘除指令。 也许它的一些软件乘法和软件除法例程可以移植到您的MCU。
还可以查看“牛顿法进行除法运算”。 我认为这种方法给出了任何我见过的除法算法中最小的可执行大小,尽管解释使它听起来比它实际上更复杂。 我听说一些早期的Cray超级计算机使用牛顿法进行除法运算。
要进行乘法运算,需要将移位后的被乘数的部分积加到累加器中,当且仅当乘数对应的比特位为1时。在循环结束时,将被乘数和乘数进行移位,并测试乘数 & 1,以确定是否需要进行加法运算。