【问题标题】:How many times will the while loop be executed?while 循环会执行多少次?
【发布时间】:2019-12-07 08:44:20
【问题描述】:

我想知道这个 while 循环会执行多少次。这是一个使用 XOR 和 AND 将两个数字相加的函数。

def Add(x, y): 

    # Iterate till there is no carry  
    while (y != 0): 

        # carry now contains common 
        # set bits of x and y 
        carry = x & y 

        # Sum of bits of x and y where at 
        # least one of the bits is not set 
        x = x ^ y 

        # Carry is shifted by one so that    
        # adding it to x gives the required sum 
        y = carry << 1

    return x 
``

【问题讨论】:

  • 添加一个计数器,在循环前初始化,循环内加1,与x一起打印/返回值?你的问题在哪里?
  • 他想知道它根据输入执行了多少次。
  • def Add(x, y): counter = 0 # 迭代直到没有进位 while (y != 0): counter +=1 # carry now contains common # set bits of x and y进位 = x & y # x 和 y 的位总和,其中至少有一个位未设置 x = x ^ y # 进位移位 1,以便 # 将其添加到 x 得到所需的总和 y = carry
  • 如果我们有这样的值:y=100010 和 x = 0,那么根据你的说法应该有 0 次迭代,但只有一次迭代。

标签: python time-complexity bit-manipulation bitwise-operators addition


【解决方案1】:

无进位加法器的算法:

function no_carry_adder(A,B)
    while B != 0:
        X = A XOR B, Bitwise-XOR of A,B.
        Y = A AND B, Bitwise-AND of A,B.
        A = X
        B = Y << 1, Multiplying Y by 2.
    return A

如您所见,while 循环一次又一次地执行这四个指令,直到B = 0,当B = 0 时,存储在A 中的二进制数就是答案。 现在的问题是找出在B = 0B 变为零之前while 循环将执行多少次。

如果我采用了天真的方式,即按照任何编程语言描述的方式编写算法,例如它会给我一个答案,但如果二进制字符串 A 中的位数和B&gt; 500

如何制定更快的算法? 我们来看看不同的案例,

  • 案例1:A = B = 0.
    在这种情况下,循环将 = 0 迭代为 B = 0 的次数。
  • 案例 2:A != 0B = 0
    在这种情况下,循环将= 0 迭代为B = 0 的次数也是如此。
  • 案例 3:A = 0B != 0
    在这种情况下,循环迭代 = 1 的次数是因为在第一次迭代之后,X = B 的值就像你用 0 对任何二进制数执行 bitwise XOR 时一样,结果就是数字本身。 Y = 0 的值,因为任何带有0 的数字的bitwise AND 都是0。所以,你可以看到Y = 0,然后是B = 0Y &lt;&lt; 1 = 0
  • 案例4:A = BA != 0B != 0时。
    在这种情况下,循环迭代= 2 的次数,因为在第一次迭代中A = 0 的值,为什么因为两个相同数字的bitwise XOR 总是0Y = B 的值,因为bitwise AND 的两个相同的数字是数字本身,然后是 B = Y &lt;&lt; 1,在第一次迭代之后,A = 0B != 0 所以这种情况变成 Case-3。因此,迭代次数将始终为2
  • 案例 5:A != BA != 0B != 0
    在这种情况下,循环迭代 = length of the longest carry-chain 的次数。

计算最长进位链长度的算法:

  • 首先使二进制字符串AB 的长度相等,如果它们不相等。

  • 我们知道最大进位序列的长度就是答案,我只需要找到我到目前为止发生的最大进位序列长度。因此,要计算它,

  • 我将从左到右迭代,即 LSB 到 MSB 并且:

    • if carry + A[i] + B[i] == 2 表示该位标记进位序列的开始,因此 ++curr_carry_sequencecarry = 1
    • if carry + A[i] + B[i] == 3 表示前一位加法转发的进位在这里被消耗,该位将产生一个新的进位,因此,进位序列的长度将重置为 1,即curr_carry_sequence = 1carry = 1
    • if carry + A[i] + B[i] == 1 or 0 表示前一位产生的进位在这里解析,它会标记进位序列的结束,因此进位序列的长度将重置为0。即curr_carry_sequence = 0carry = 0
  • 现在如果curr_carry_seq 的长度是&gt; 而不是max_carry_sequence,那么你更新max_carry_sequence

  • 答案是max_carry_sequence + 1

源代码参考No Carry Adder Solution

附: No-Carry Adder 的平均情况分析可以参考论文:Average Case Analysis of No Carry Adder: Addition in log(n) + O(1)Steps on Average: A Simple Analysis

【讨论】:

    【解决方案2】:

    while 循环执行多少次没有固定答案。当从一个位置到另一个位置有进位时,总是执行 while 循环。因此,您需要知道数字在二进制中的样子。但是你可以肯定地说,最大可能的执行次数是多少。它是较大数字的长度为位+ 1。为什么?因为如果这是进位可以最大发生的数字。让我们以 add(1,7) = 8 (001 + 111 = 1000) 为例。第一个位的进位被传递到第二个位置,然后传递到第三个位置,然后传递到第四个位置。 4 次迭代 this 等价于 7 和 that + 1 = 4 的长度。

    【讨论】:

    • 如果我们确切地知道二进制数字的样子,你将如何计算 while 循环在没有实际运行的情况下运行了多少次?
    • 计算执行的问题是在一次迭代中可以一次添加许多进位,例如 5+5 (101 + 101) 需要两次迭代,首先获取所有进位然后添加它们。在这种情况下,既可以添加进位,也不会产生新的进位。另一方面,如果我们查看 3+1 (11+1),即使我们只有两个载波,我们也需要 3 次迭代。第二次迭代将产生一个新的进位。于是又进行了一次迭代。您需要查看有多少值受到其他值的影响,并减去一次可以同时添加的值。所以最简单的方法就是做算法。
    • 如果我们有这样的值:y=100010 和 x = 0,那么根据你的说法应该有 0 次迭代,但只有一次迭代