我试图在乘以两个二进制值时找出关于Karatsuba算法的问题。我想成倍增加:
10110110 * 11001000
我需要弄清楚使用Karatsuba算法时完成哪些子问题。我知道算法是
x * y = ((2^n)(xHyH))+(2^(n/2))(xHyL + xLyH) + xLyL
但每个值代表什么?如何从二进制值转到xH,yH,xL,
和yL
?感谢。
答案 0 :(得分:0)
重点是将你的数字分成低位和高位:
x = 10110110b
xh= 1011b
xl= 0110b
x = xh<<4 + xl
数字基数并不重要(但必须具有相同的基数),因为您处理Karatsuba中的数字,因此您可以使用任何基数。您只需要在所使用的基础上定义所需的操作。因此,例如,如果您的数字是十进制字符串,则无需将其转换为二进制。
所以关键是从第一次运行中将pad x,y
从右边零填充到2位宽度的公共功率(如果还没有完成),或者在每次运行中只调整到通用大小以避免/处理舍入问题分裂时。由于数字通常是某种寄存器或编程语言变量类型,因此它们通常已经为零填充。如果是bignums或字符串,则无法保证。
然后在每一步中,将x,y
分成两半并计算等式。
这些方程涉及乘法,所以它递归地调用相同的karatsuba乘法,但现在使用半位宽数字。
一旦达到x,y
的可计算位宽,就直接计算乘法而不是使用Karatsuba(这通常是 ALU 支持乘法的最高字位宽度。)< / p>
当您输入x,y
时,数字已经是8位,大多数 CPU 可以直接处理,不需要Karatsuba。如果你没有乘法或想要尝试这些东西,你可以细分到位宽1并使用真值表:
0*0=0
0*1=0
1*0=0
1*1=1
现在问题是你需要在可能超过其位宽的位置(在部分乘法之后)添加数字块。 (如果你添加两个4位数字,结果可能是9位)并且在Karatsuba方程式中你添加了很多东西,所以你需要记住你需要的不仅仅是单个进位(我认为两个应该削减它,我改为使用双增量(检查溢出两次),这适用于我)。
此外,如果您使用限制ALU位宽和更高级别的语言(如C / C ++),您可能根本无法进行携带,需要解决它,例如:
这里有小例子(以及其他一些方法):
如果您想要测量速度,请记住Karatsuba的开销比天真O(n^2)
更大,但只有足够大的数字才会加倍......
现在回到你的分裂问题。全部取决于您的号码是如何存储的。所以在字符串的情况下,你用字符串函数分割它们。如果是数字,你可以将它们放在一个已经用二进制表示的变量中(在硅片级别上),这样你就可以使用位移和掩码。在C ++中8 -> 4 + 4
位的情况下,它是这样完成的:
x = your number;
xl = x&15; // bitwise AND
xh = x>>4; // shift right arithmetic SRA by 4 bits
其中15 = (1<<4)-1
和4
是您要拆分的位宽。因此,如果您想要n
位宽,则可以重写为:
x = your number;
n = new bit width (half of x bitwidth)
xl = x&((1<<n)-1); // bitwise AND
xh = x>>n; // shift right arithmetic SRA by 4 bits
您也可以将递归中的n
作为操作数传递,然后将其加n>>=1
一半,然后停在n=0
上,这意味着您已经在1位宽度上并且没有理由拆分...