Algorithm 如何最大限度地减少添加的数量?

Algorithm 如何最大限度地减少添加的数量?,algorithm,Algorithm,例如:如果输入是,5*8,以下方法之一,可以加上较大的数字或较小的次数,这就是答案。但我如何才能最大限度地减少添加的数量 我喜欢Codor关于使用移位和零加法的建议 但是如果你真的只使用加法,而不使用移位、日志、减法等其他运算,我相信计算a*b的最小加法数将是: Multiply two numbers without using * operator, and with minimum number of additions 在哪里 numbits(n)是的二进制表示形式中的个数 整数n

例如:如果输入是,5*8,以下方法之一,可以加上较大的数字或较小的次数,这就是答案。但我如何才能最大限度地减少添加的数量

我喜欢Codor关于使用移位和零加法的建议

但是如果你真的只使用加法,而不使用移位、日志、减法等其他运算,我相信计算a*b的最小加法数将是:

Multiply two numbers without using * operator, and with minimum number of additions
在哪里

  • numbits(n)是的二进制表示形式中的个数 整数n

    • 例如,numbits(4)=1,numbits(5)=2,等等
  • int[x]是浮点x的整数部分

    • 例如,int[3.9]=3
现在,我们是如何到达那里的?首先看一下您的原始示例。您至少可以将添加项分组在一起。例如

min{int[log2(a+1)] + numbits(a), int[log2(b+1)] + numbits(b)} - 2
为了概括这一点,如果需要仅使用使用a的加法或已计算的加法结果将a乘以b,则需要:

  • int[log2(b+1)]-1加法,计算所需的所有2^n.a中间数

    • 在您的示例中,int[log2(5+1)]-1=2:您需要两个加法来计算16和32
  • numbits(b)-1个加法,将所有中间结果相加,其中numbits(b)是b的二进制表示中的一个数

    • 在您的示例中,5=2^2+2^0所以numbits(5)-1=1:您需要一个加法来完成32+8
有趣的是,这意味着你的声明

8+8=16
16+16=32
32+8=40
并非总是将添加次数减至最少的配方

例如,如果需要计算2^9*(2^9-1),则基于(2^9-1)计算加法比基于2^9计算加法要好,即使2^9更大。最快的方法是:

add the bigger number smaller number of times
然后

x = (2^9-1) + (2^9-1)
8次,共9次添加

如果将2^9添加到自身,则需要8个加法才能首先获得所有2^k*2^9,然后再添加8个加法才能将所有这些数字相加,总共16个加法。

减少加法数量的一个策略是按层次添加内容。这与经典幂算法中使用的策略相同,它遵循相同的技术来最小化乘法次数

假设你需要

x = x+x
一旦你计算出m2=a+a,你就可以把它代入上面的加法中,得到

M = a * 8 = a + a + a + a + a + a + a + a
然后您可以计算m4=m2+m2,并得出

M = m2 + m2 + m2 + m2
因此,结果是在
3
加法中计算的,而不是原来的
8
。但是,向自身添加值可以用左移位
1
位来代替(如果允许的话),这将大大减少添加的次数

通过分析其中一个被乘数的二进制表示,可以优雅地实现该技术(与幂算法中通常实现的完全相同)。例如,如果您需要计算
a*b
,您可以这样做

M = m4 + m4
intm=0;

对于(int m=a;b!=0;b>>=1,m一个更好的例子是
5*7
。这本质上是使用旧方法的二进制乘法,但需要巧妙地选择乘法器

  111
x 101
------
  111
 000x    <== This is not an addition, only a left shift
111xx
-------
100011   <== 2 additions totally.
-------
如果我们可以使用左移位,但这不算作加法:选择位数较小的数字作为乘法器。在这种情况下,这将是
5

int M = 0;
for (int m = a; b != 0; b >>= 1, m <<= 1)
  if ((b & 1) != 0)      
    M += m;

上面有三个移位和零加法。

假设a与b相乘,我们将结果存储在res中,只有当b为奇数时,我们才将a与res相加,否则继续将b除以2并将a乘以2。这在循环中完成,直到b变为0。乘法和除法可以使用位运算符完成

让两个给定的数字分别为“a”和“b” 1) 将结果“res”初始化为0。 2) 在“b”大于0时执行以下操作 a) 如果“b”为奇数,则将“a”添加到“res” b) 将“a”加倍,将“b”减半
3) 返回'res'

渐近?用这个看起来像是家庭作业,比如用二进制在纸上做乘法,看看是否会出现算法。你能用什么运算符?你会使用列表吗?你能在计算后存储值吗(记忆)?取对数,做一个加法,取反对数。如果允许零为常数,你可以用两个减法(否则,三个)代替任何加法。如果允许减法,请查看Booth-2(基数-4-Booth)和非相邻形式(NAF)。使用ab=((a+b)²-(a-b)²)/4。分解乘数。看一看没有乘法(或比加法慢得多)的机器的编译器为常数乘法生成了什么。这不会减少加法的数量。求幂算法也不会执行最小的乘法运算。@IVlad:是的,它当然会最小化乘法运算。也许可以为某些输入实现更好的最小值,但这实际上是微不足道的。在添加的情况下,用
m立即替换
m+=m
的能力不会最小化,尽管它通常“足够接近”。存在更好的解决方案的最小值是15。如果在某些情况下可以实现更好的最小值,那么根据定义,您不会最小化它。这只是一个启发。这在实践中可能还可以,但在实践中,您也可以只使用
*
运算符(即使在实现大数字时,您也可以使用
*
来模拟小学长乘法算法)。这是一个很好的答案,但针对的是另一个问题。这与我的答案完全相同,是从不同的实践角度给出的。在我发表这篇文章之前,我没有看到你写了什么。我认为这里唯一的附加值是关于乘数的选择。正如你所看到的,当其他答案出现时,我已经迷失在格式上:)无论如何,乘法的方法真的很少(当处理两个的乘法时)
    101
 x 1000
 -------
    000
   000x  <== left shift
  000xx  <== left shift
 101xxx  <== left shift
--------
 101000  <== no addition needed, so 3 additions totally.
--------