如何最大限度地减少添加次数?

时间:2015-07-29 17:36:42

标签: algorithm

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

例如:如果输入为5 * 8,则可以使用以下方法之一添加较大数量的较小次数,这将是答案。但是,如何最大限度地减少添加次数?

4 个答案:

答案 0 :(得分:2)

最小化减少添加次数的一种策略是添加层次结构。这与经典功率算法中使用的策略相同,后者采用相同的技术来最小化乘法次数。

假设你需要

$rootScope.$on('$routeChangeSuccess', function(e, curr, prev) {
    if (Object.getPrototypeOf($route.current) === $route.routes['/Home']) {
         // do something when route changes to /Home
    }

    else if (Object.getPrototypeOf($route.current) === $route.routes['/About']) {
         // do something when route changes to /About
    }
}

计算M = a * 8 = a + a + a + a + a + a + a + a 后,您可以将其替换为上述添加内容并获取

m2 = a + a

然后您可以计算M = m2 + m2 + m2 + m2 并到达

m4 = m2 + m2

因此,结果是在M = m4 + m4 次添加而非原始3中计算的。但是,向自身添加一个值可以替换为左移8位(如果允许),这大大减少了添加次数。

这种技术可以通过分析其中一个被乘数的二进制表示来优雅地实现(正如它通常在幂算法中实现的那样)。例如。如果您需要计算1,您可以这种方式进行计算

a * b

此类实现将使用的添加总数是int M = 0; for (int m = a; b != 0; b >>= 1, m <<= 1) if ((b & 1) != 0) M += m; 1位的总数。它将b乘以5加1。

请注意,为了实现此策略提供的最低添加次数,将较大的数字乘以较小的数字不一定是最佳选择。例如。乘以8使用的加法次数少于乘以8

答案 1 :(得分:1)

我喜欢Codor关于使用轮班和零添加的建议!

但是如果你真的只能使用加法而没有其他操作,如移位,日志,减法等,我相信计算a * b的最小数量将是:

min{int[log2(a+1)] + numbits(a), int[log2(b+1)] + numbits(b)} - 2

,其中

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

    • 例如,numbits(4)= 1,numbits(5)= 2等
  • int [x]是float x

    的整数部分
    • 例如,int [3.9] = 3

现在,我们是如何到达那里的?首先看看你的原始例子。您至少可以将添加内容组合在一起。例如。

8+8=16
16+16=32
32+8=40

为了概括这一点,如果你需要通过仅使用使用a的加法或已经计算的加法结果来乘以b次,你需要:

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

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

    • 在你的例子中,5 = 2 ^ 2 + 2 ^ 0所以numbits(5)-1 = 1:你需要增加一个来做32 + 8

有趣的是,这意味着你的陈述

add the bigger number smaller number of times

并不总是减少添加次数的方法。

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

x = (2^9-1) + (2^9-1)

然后

x = x+x

总共9次添加8次。

如果您将2 ^ 9添加到自身,则需要8次添加才能首先获得所有2 ^ k * 2 ^ 9,然后再增加8次添加以将所有这些数字加在一起,总共添加16次。 / p>

答案 2 :(得分:1)

更好的例子是5 * 7。这本质上是使用旧方法的二进制乘法,但巧妙地选择了乘数。

如果我们可以使用左移并且不算作加法:选择位数较小的数字作为乘数。在这种情况下,这将是5

  111
x 101
------
  111
 000x    <== This is not an addition, only a left shift
111xx
-------
100011   <== 2 additions totally.
-------

如果我们不能使用左移:请注意,左移与加倍/加法相同。然后我们将不得不使用略有不同的策略。由于被乘数将与(position of MSB - 1)移位相同的次数,因此加法的数量将是具有较小值(position of MSB - 1) + (number of bits set)的数字。如果是5 * 8,则值分别为(3-1) + 2 = 4(4-1) = 3。较小的是8,因此将其用作乘数。

    101
 x 1000
 -------
    000
   000x  <== left shift
  000xx  <== left shift
 101xxx  <== left shift
--------
 101000  <== no addition needed, so 3 additions totally.
--------

以上有三个班次和零添加。

答案 3 :(得分:0)

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

让两个给定的数字为&#39; a&#39;和&#39; b&#39; 1)初始化结果&#39; res&#39;为0。 2)在&#39; b&#39;大于0    a)如果&#39; b&#39;是奇怪的,添加&#39; a&#39;到了&#39; res&#39;    b)Double&#39; a&#39;和减半&#39; b&#39; 3)返回&#39; res&#39;。