我正在使用移位和加法编写一个软乘法函数调用。现有的函数调用如下:
unsigned long __mulsi3 (unsigned long a, unsigned long b) {
unsigned long answer = 0;
while(b)
{
if(b & 1) {
answer += a;
};
a <<= 1;
b >>= 1;
}
return answer;
}
虽然我的硬件没有倍增器,但我有一个硬移位器。移位器一次最多可以移位16位。
如果我想充分利用我的16位移位器。有关如何调整上述代码以反映我的硬件功能的任何建议?给定的代码每次迭代仅移位1位。
16位移位器可以一次将32位无符号长值移位16个位置。 sizeof(无符号长整数)== 32位
答案 0 :(得分:1)
使用16位移位可以帮助您使用以下方法进行小幅度的增强:
(U1 * P + U0) * (V1 * P + V0) = = U1 * V1 * P * P + U1 * V0 * P + U0 * V1 * P + U0 * V0 = = U1 * V1 * (P*P+P) + (U1-U0) * (V0-V1) * P + U0 * V0 * (1-P)
如果P是2的便利功率(例如,2 ** 16,2 ** 32),那么乘以它就是快速移位。这减少了从4到3的较小数字的乘法,并且递归地,O(N **(3/2))而不是O(N ** 2)对于非常长的数字。
至少在Knuth的TAoCP中描述了这种方法。还有更多高级版本。
对于小数字(例如8乘8位),如果你有足够的快速ROM,下面的方法很快:
a * b = square(a+b)/4 - square(a-b)/4
如果要列表int(square(x)/4)
,则无符号乘法需要1022个字节,签名一个需要510个字节。
答案 1 :(得分:0)
上面的代码正在以传统方式,即我们在小学学习的方式成倍增加:
EX:
0101
* 0111
-------
0101
0101.
0101..
--------
100011
当然,如果你没有乘法运算符或1位移位器,你就无法接近它!
但是,您可以通过其他方式执行此操作,例如循环:
unsigned long _mult(unsigned long a, unsigned long b)
{
unsigned long res =0;
while (a > 0)
{
res += b;
a--;
}
return res;
}
它很实用,但它可以满足您的需求,无论如何,如果您有更多限制(如计算时间......),您可以考虑其他方法。
答案 2 :(得分:0)
基本方法是(假设换1): -
取决于你的硬件...
但你可以试试: -
然后: -
union Data32
{
unsigned long l;
unsigned short s[2];
};
unsigned long shiftleft32(unsigned long valueToShift, unsigned short bitsToShift)
{
union Data32 u;
u.l = valueToShift
u.s[0] <<= bitsToShift;
u.s[0] |= (u.s[1] >> (16 - bitsToShift);
u.s[1] <<= bitsToShift
return u.l;
}
然后反向移动
答案 3 :(得分:0)
移位多位的能力不会有多大帮助,除非你有硬件乘法,比如说8位x 8位,或者你可以买一些RAM / ROM来做(如)4位乘4位乘以查找。
通过交换参数以使乘数更小,可以帮助直接转换和添加(正如您所做)。
如果您的机器通常更快地做16位的事情,那么就要对待32位&#39; a&#39; as&#39; a1:a0&#39;一次16位,类似地&#39; b&#39;,你可能能够在相同的一些周期。你的结果只有32位,所以你不需要做&#39; a1 * b1&#39; - 虽然其中一个或两个可能为零,但胜利可能不大!此外,您只需要16位的&#39; a0 * b1&#39;,因此可以完全16位完成 - 但如果b1(假设b <= a)通常为零,则不是也是一场大胜利。对于&#39; a * b0&#39;,您需要一个32位&#39; a&#39;并且32位添加到&#39;回答&#39;,但您的乘数仅为16位...这可能有助于也可能没有帮助。
跳过乘数零运行可能有所帮助 - 取决于处理器和乘数的任何属性。
FWIW:做魔术&#39; a1 * b1&#39;,&#39;(a1-a0)*(b0-b1)&#39;,&#39; a0 * b0&#39;在我的小经验中,通过轮班,加法和减法将结果结合起来是一场绝对的噩梦... ......(a1-a0)&#39;&#39;(b0-b1)& #39;并且他们的产品必须受到尊重,这使得看起来像一个可爱的伎俩有点混乱。当你完成它以及添加和减去时,你必须有一个强大的缓慢乘法,以使它全部值得!当乘以非常非常长的整数时,这可能会有所帮助......但是内存问题可能占主导地位...当我尝试它时,它会令人失望。