【问题标题】:Need clarification about this loop performing multiplication需要澄清这个循环执行乘法
【发布时间】:2013-09-29 14:37:46
【问题描述】:
int x, y; // x is a non-negative integer 
p = 0;
while (x > 0)
{
    if ( x % 2 == 1 )
       p = p + y;
    y = y*2;
    x = x/2;
}
// p == a*b here

我知道这个循环使用代数找到“a”和“b”的乘积:

a * b = (1/2)a * 2b

但我看不懂代码:

if ( x % 2 == 1 )
    p = p + y;

我希望有人能解释为什么在 x 的奇数值上将“p”分配为“p + y”。

【问题讨论】:

    标签: c++ algorithm loops math multiplication


    【解决方案1】:
    while (x > 0) {
        if (x % 2 == 1)
            p = p + y;
        y = y*2;
        x = x/2;
    }
    

    想象x = 4, y = 5

    迭代:

    1. x 是偶数,y = 10,x = 2(即x可以除,y应该加倍
    2. x 是偶数,y = 20,x = 1
    3. x 是奇数,p = 20,y = 40,x = 0(即 x 不能再除,y 应该添加到 p
    4. x > 0false,循环结束

    p = 4 * y

    现在假设x 开头是奇数,假设x = 5,y = 2:

    1. x 是奇数,p = 2,y = 4,x = 2
      (5/2 = 2.5,x 的新值将向下舍入,y 应在加倍之前添加
    2. x 是偶数,y = 8,x = 1
    3. x 是奇数,p = 10,y = 16,x = 0

    p = y + 4*y

    第一个y 是原因,在结果加倍之前将其添加到结果中(1 * y)在这种情况下等同于0.5 * (2 * y)

    【讨论】:

      【解决方案2】:

      因为这些是整数,所以a / 2 将是一个整数。如果a 是奇数,则该整数已向下舍入,并且您在循环的下一次迭代中缺少一半b,即循环的当前迭代中的一个整数b(因为@987654325 @[y] 每次翻倍)。

      【讨论】:

        【解决方案3】:

        如果 x 是奇数,x = x/2 会将 x 设置为比 x/2 小 0.5(因为整数除法会将其向下舍入)。 p 需要进行调整以允许这样做。

        【讨论】:

          【解决方案4】:

          将乘法视为重复加法,x*y 是将 y 加在一起 ​​x 次。这也与将 2*y 相加 x/2 次相同。从概念上讲,如果 x 是奇数,它的含义有些不清楚。比如x=5,y=3,加2.5倍是什么意思?代码注意到 x 何时为奇数,将 y 添加进去,然后 y=y*2 和 x=x/2。当 x 是奇数时,这会丢弃 0.5 部分。所以在这个例子中,你加一次 y,然后 x 变成 2(不是 2.5),因为整数除法会丢弃分数。

          在每个循环结束时,对于 p、x 和 y 的当前值,您将看到原始 x 和 y 的乘积等于 p + x*y。循环迭代直到 x 为 0,结果完全在 p 中。

          如果您制作一个表格并在每次循环中更新它,这也有助于查看发生了什么。这些是每次迭代开始时的值:

          x | y  | p
          ----------
          5 | 3  | 0
          2 | 6  | 3
          1 | 12 | 3
          0 | 24 | 15
          

          【讨论】:

            【解决方案5】:

            这通过观察(例如)y * 10 = y * 8 + y * 2 起作用。

            这很像在学校里在纸上做乘法。例如,要乘以 14 x 21,我们一次乘一位数(并在需要的地方左移一个位置),因此我们添加 1x14 + 2 x 14(左移一位数)。

                14
              x 21
              ----
                14
               280
            

            在这里,我们正在做几乎相同的事情,但使用二进制而不是十进制。右移与奇数无关,而与简单地查找数字中的哪些位已设置有关。

            当我们将一个操作数右移以确定是否设置了位时,我们也会将另一个操作数左移,就像我们在纸上进行十进制算术时添加零来左移数字一样。

            因此,以二进制形式查看内容,我们最终会得到如下结果:

                  101101
                x  11010
                --------
                 1011010
            +  101101000
            + 1011010000
            

            如果我们愿意,而不是将操作数向右移动,我们可以将掩码向左移动,这样我们就可以将 and1 重复使用 and1,然后使用 @987654328 @,然后是4,依此类推(事实上,这样可能更有意义)。然而,无论好坏,在汇编语言中(通常会做这种事情),移位操作数并为掩码使用常量通常比将掩码加载到寄存器中并在需要时移位它要容易一些。

            【讨论】:

              【解决方案6】:

              您应该将 x 重写为 2*b+1(假设 x 是奇数)。那么

              x*y = (2*b+1)*y = (2*b)*y + y = b*(2*y) + y = (x/2)*(2*y) + y
              

              其中 (x/2) 表示整数除法。以这种方式重写操作后,您会看到 x/2、2y 和 +y 出现。

              【讨论】:

                猜你喜欢
                • 2017-11-26
                • 1970-01-01
                • 2018-12-31
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2012-01-11
                • 2011-11-09
                相关资源
                最近更新 更多