我正在尝试使用32位二进制乘法器的C ++实现。我知道只有一种方法可以做到这一点
1011 (this is 11 in decimal)
x 1110 (this is 14 in decimal)
======
0000 (this is 1011 x 0)
1011 (this is 1011 x 1, shifted one position to the left)
1011 (this is 1011 x 1, shifted two positions to the left)
1011 (this is 1011 x 1, shifted three positions to the left)
=========
10011010 (this is 154 in decimal).
还有另一种方法可以做到这一点,因为我不得不对更长的二进制数进行操作,因此编码不是很麻烦吗?
答案 0 :(得分:0)
您可以使用Booth的乘法算法。有关维基百科的更多信息:http://en.wikipedia.org/wiki/Booth%27s_multiplication_algorithm
答案 1 :(得分:0)
由于积分类型的隐式乘法是二进制乘法,您可以直接利用它来将数字视为基数2 8 ,2 16 或更高,而不是基数2 1 。
如果您假设8位数字(乘以unsigned char
s),则下面的24位示例不如您在问题中发布的4位乘法复杂。
a1 a2 a3 (this is a 3 byte value)
x b1 b2 b3 (this is another 3 byte value)
======
xx xx xx xx (this is a x b3)
xx xx xx xx (this is a x b2, shifted 8 bits to the left)
xx xx xx xx (this is a x b1, shifted 16 bits to the left)
=================
xx xx xx xx xx xx (this is the result).
您可以将上面的“字节”替换为short
或long
,并相应地调整班次。
请确保将被乘数转换为足够大的类型,以便在乘法之前保持进位。
答案 2 :(得分:0)
是的,您可以通过使用循环来完成此任务。
假设类型long
是32位,因此long * long的结果是64位。
例如,如果您有long A
蚂蚁long B
,并且您想要计算a*b
首先,将结果定义为long long result = 0;
。
然后检查B的每一位,如果位为1,则将A << X
添加到result.Where是位的索引。
一个循环可以实现这一目标。
long long AA = A;// convernt A to AA to avoid overflow
for( int index=0;i<32;++index )
{
if( B & 0x1 )
result += AA;
AA <<= 1;
B >>= 1;
}
我希望我没有犯错,这个想法可以帮助你。
答案 3 :(得分:0)
嗯,任意精度和大数的(正确和有效)实现是非常麻烦的,并且在生产代码中使用它通常建议更好地使用经过测试的框架(例如,{{ 3}},boost等。)
但是,如果您自己实现它,我不会将数字存储为位序列,而是存储为unsigned int
等机器字序列,以充分利用您的硬件ALU功能。所以每个单词都代表了一些位,你的ALU知道如何将它们相乘。
请注意,当您将数字乘以n
位数(基数无关)时,您会得到一个数字为2n
的数字,例如99 * 99 = 9801(基数10),0xFF * 0xFF = 0xFE01(基数16)。
因此,如果您的系统std::uintmax_t
为std::uint64_t
,则可以将您的号码存储为std::uint32_t
的序列。乘以两位数将它们转换为std::uint64_t
并乘以它们。高32位将成为下一个更高位的乘法运算的部分。 (实际上,您也可以直接乘以std::uintmax_t
个变量,但获取结果的高位通常有点棘手并且涉及内联汇编以访问相应的EDX\RDX
寄存器。)
有了这些知识,gmp的实现应该很简单:只需遍历数字a[i]
的所有数字a
,并将每个数字乘以数字b
(不要)忘记传播携带)。将结果向上移动i
位数,并将所有内容添加到最终结果中。
注意,该算法在原始乘法的数量方面具有二次复杂度。如果你有(非常,非常)大数字,你也可以切换到更复杂的方法,如Karatsuba甚至FFT和Schönhage-Strassen。但在这种情况下,我真的建议使用库。