【问题标题】:How do you determine if there is even 1s in a number's binary representation using C? [duplicate]如何使用 C 确定数字的二进制表示中是否有偶数 1? [复制]
【发布时间】:2013-10-22 18:34:41
【问题描述】:

已经有关于计算一个数字中有多少个1s的问题,但是这个问题是关于判断1s是偶数还是奇数。

不允许使用任何循环或条件(包括 switch)语句。此外,应避免除法、乘法或取模运算符。更具体地说,我们可以假设它是一个 32 位无符号整数。

实际上我已经有了一个实现,但我无法弄清楚它工作的原因。任何证明其正确性或任何新想法的证据都会非常有帮助。

int even_ones(unsigned x)
{
    x ^= x>>16;
    x ^= x>>8;
    x ^= x>>4;
    x ^= x>>2;
    x ^= x>>1;

    return !(x & 1);
}

【问题讨论】:

    标签: c bit-manipulation parity


    【解决方案1】:

    Here are several variants 快速计算一个字节或一个字的奇偶校验。究竟哪种方法最快取决于您的 CPU 以及不同的基本操作相对于彼此的速度。因此,如果这在某种程度上是您的应用程序的瓶颈,您应该对每一个进行分析,以找出哪一个在您的目标机器上运行得最好。

    您的解决方案与"compute parity in parallel" 实现非常相似,只是最后没有进行巧妙的优化。这里发生的情况是,在每一步中,您将一半位与另一半位进行异或运算,直到只剩下一位。如果有偶数个 1,则单词的奇偶性为 0,如果有奇数个 1,则奇偶性为 1;或者等价地,一个单词的奇偶校验只是单词中所有位的异或。

    由于 XOR 运算符是可交换的和关联的,我们可以重新排序单词中的所有位是如何异或在一起的。因此,我们不是通过将每个位单独异或到结果中来计算所有位的异或,而是将高半位与低半位进行异或,将我们关心的位数减少一半;当还剩一点时,我们就完成了。

    【讨论】:

      【解决方案2】:

      我假设您知道独占或^ 操作的作用——如果两个位设置为相同的值,则结果为0——否则为1。因此,当我有两个一位数字 A 和 B 时,如果 A 和 B 都是 0 或两者都是 1A^B 将为零。换句话说 - AB 的总和是偶数...

      现在让我们一次执行两位:C 和 D 是两位数。以下是可能的组合:

      C    D    C^D
      00   00   00   even
      01   00   01    odd
      10   00   10    odd
      11   00   11   even
      00   01   01    odd
      01   01   00   even
      10   01   11   even
      11   01   10    odd
      00   10   10    odd
      01   10   11   even
      10   10   00   even
      11   10   01    odd
      00   11   11   even
      01   11   10    odd
      10   11   01    odd
      11   11   00   even
      

      如您所见 - 每个实例中的操作都会将位数减少一半,如果您从奇数开始,则生成的 1 位数是奇数(因为 1s 对取消出,但所有其他都没有改变)。

      现在应该很明显了,为什么当您从较大的数字(4 位、8 位、16 位)开始时,同样的事情仍然是正确的。本质上,您的算法从 32 位数字开始,并将其拆分为两个 16 位数字。通过摆脱“双1”,它将位数减少了一半;然后对剩下的一半进行操作,并重复直到只剩下一个位。通过测试该位是 1(奇数)还是 0(偶数),您会得到答案。

      如果不清楚,像x ^= x>>16 这样的操作实际上会将前 16 位移动到后 16 位,并在那里产生异或。它实际上并没有清除最高位,所以“留下了一个烂摊子”。但是该算法忽略了接下来的混乱。请参阅以下内容(为简单起见以 8 位开头):

      x =      abcdefgh 
      x >> 4 = 0000abcd
      new x  = abcdijkl
      x >> 2 = 00abcdij
      new x  = abmnopqr
      x >> 1 = 0abmnopq
      new x  = astuvwxy
      

      其中最后一位yrq的异或,又是l,jk,i的异或;它们分别是 h,df,bg,ce,a 的 XOR。如您所见,您最终得到了所有位的异或;正如我上面解释的那样,这意味着“全偶数”或“全奇数”,具体取决于最低有效位现在是1 还是0

      我希望这会有所帮助。

      【讨论】:

        【解决方案3】:

        请注意,此 XOR 是最高有效 16 位与最低有效 16 位。:

        x ^= x>>16;
        

        然后该系列继续将第二个最低有效 8 位与最低有效 4 位进行异或运算,注意最高有效 16 位现在只是垃圾,无论发生什么都可以忽略:

        x ^= x>>8;
        

        以此类推,我们继续对第二个最低有效 4 位与最低有效 4 位进行异或运算,直到达到 1 位;到目前为止,除了最低有效位之外的所有位都是垃圾,最后一行只需使用按位和 1 来获取最低有效位并将其翻转以进行均匀性测试。

        也许这样写会更容易理解:

        int even_ones(unsigned x)
        {
            a = (x ^ x>>16) & 0x0000FFFF;
            b = (a ^ a>>8)  & 0x000000FF;
            c = (b ^ b>>4)  & 0x0000000F;
            d = (c ^ c>>2)  & 0x00000003;
            e = (d ^ d>>1)  & 0x00000001;
            return !(e&1);
        }
        

        为什么会这样?因为 XOR 相当于没有进位的按位加法。

        【讨论】:

          【解决方案4】:

          希望对你有帮助::

             enum {
                EVEN,
                ODD
              } even_odd;
          
          unsigned int check_even_odd_no_of_ones(unsigned int num)
          {
            if(num_of_ones(num) & 1)
              return ODD;
            else
              return EVEN;
          }
          

          谢谢

          【讨论】:

          • 这并不能真正回答问题。
          • 这只是逻辑,我想。这里没有提到完整的代码..
          猜你喜欢
          • 2010-10-16
          • 2017-04-13
          • 2020-02-28
          • 2021-10-26
          • 1970-01-01
          • 1970-01-01
          • 2018-06-23
          • 2023-04-03
          • 1970-01-01
          相关资源
          最近更新 更多