给定unsigned int,获取set位的“索引”的最快方法是什么?

时间:2008-09-16 02:39:51

标签: algorithm bit-manipulation

因此,例如0110有1位和2位,1000有3位,1111有0,1,2,3位

10 个答案:

答案 0 :(得分:7)

如果实际上只有4位,那么最快的方法肯定会涉及查找表。毕竟只有16种不同的可能性。

答案 1 :(得分:6)

互联网上所有位黑客的最佳参考资料 - bit twiddling hacks

答案 2 :(得分:4)

我会将其向下移动并测试循环中最不重要的位。使用32位掩码(或无符号整数的长度)可能会更快进行测试。

/阿伦

答案 3 :(得分:4)

for( int i = 0; variable ; ++i, variable >>= 1 ) {
  if( variable & 1 )
    // store bit index - i
}

答案 4 :(得分:1)

如果是.NET,你必须经常使用它,我想要一个漂亮的流畅界面。

我会创建以下类(对BitTools这个名称并不完全满意)。

[Flags]
public enum Int32Bits
{
    // Lookup table but nicer
    None = 0,
    Bit1 = 1,        Bit2  = 1 << 1,  Bit3  = 1 << 2,  Bit4  = 1 << 3,  Bit5  = 1 << 4,  Bit6  = 1 << 5,  Bit7  = 1 << 6,  Bit8  = 1 << 7,
    Bit9  = 1 << 8,  Bit10 = 1 << 9,  Bit11 = 1 << 10, Bit12 = 1 << 11, Bit13 = 1 << 12, Bit14 = 1 << 13, Bit15 = 1 << 14, Bit16 = 1 << 15,
    Bit17 = 1 << 16, Bit18 = 1 << 17, Bit19 = 1 << 18, Bit20 = 1 << 19, Bit21 = 1 << 20, Bit22 = 1 << 21, Bit23 = 1 << 22, Bit24 = 1 << 23,
    Bit25 = 1 << 24, Bit26 = 1 << 25, Bit27 = 1 << 26, Bit28 = 1 << 27, Bit29 = 1 << 28, Bit30 = 1 << 29, Bit31 = 1 << 30, Bit32 = 1 << 31,
}

public static class BitTools
{
    public static Boolean IsSet(Int32 value, Int32Bits bitToCheck)
    {
        return ((Int32Bits)value & bitToCheck) == bitToCheck;
    }

    public static Boolean IsSet(UInt32 value, Int32Bits bitToCheck)
    {
        return ((Int32Bits)value & bitToCheck) == bitToCheck;
    }

    public static Boolean IsBitSet(this Int32 value, Int32Bits bitToCheck)
    {
        return ((Int32Bits)value & bitToCheck) == bitToCheck;
    }
    public static Boolean IsBitSet(this UInt32 value, Int32Bits bitToCheck)
    {
        return ((Int32Bits)value & bitToCheck) == bitToCheck;
    }
}

您可以通过以下方式使用它:

static void Main(string[] args)
{
    UInt32 testValue =  5557; //1010110110101;

    if (BitTools.IsSet(testValue, Int32Bits.Bit1))
    {
        Console.WriteLine("The first bit is set!");
    }
    if (testValue.IsBitSet(Int32Bits.Bit5))
    {
        Console.WriteLine("The fifth bit is set!");
    }
    if (!testValue.IsBitSet(Int32Bits.Bit2))
    {
        Console.WriteLine("The second bit is NOT set!");
    }
}

对于每个(U)Int大小,您可以创建另一个Int * Bits枚举以及IsSet和IsBitSet的正确重载。

编辑:我误读了,你说的是无符号的整数,但在这种情况下它是一样的。

答案 5 :(得分:0)

取决于你最快的意思。

如果您的意思是“简单编码”,在.NET中您可以使用BitArray类并将每个位称为布尔值true / false。

BitArray Class

答案 6 :(得分:0)

@Allan Wind ......

不需要额外的位移。不进行位移更有效,因为比较最低有效位与比较第二最低有效位同样有效,依此类推。进行一点移位只是将所需的位操作加倍。

firstbit = (x & 0x00000001) 
secondbit = (x & 0x00000002) 
thirdbit = (x & 0x00000004)   //<-- I'm not saying to store these values, just giving an example. 
...

无论如何,x86系统上的所有操作都是使用32位寄存器完成的,因此单个位比较与32位比较一样有效。

更不用说拥有循环本身的开销。

问题可以在恒定数量的代码行中完成,代码是在x86还是x64上运行,我所描述的方式更有效。

答案 7 :(得分:0)

您可以采用迭代遍历int的字节的混合方法,使用查找表来确定每个字节中的设置位的索引(分解为半字节)。然后,您需要向索引添加偏移量以反映其在整数中的位置。

即。假设您从32位int的MSB开始。高位半字节索引我将调用upper_idxs,低位半字节索引我将调用lower_idxs。然后你需要为lower_idxs的每个元素添加24,并为upper_idxs的每个元素添加28。下一个字节将被类似地处理,除了偏移量分别为16和20,因为该字节是8位“向下”。

对我而言,这种方法似乎是合理的,但我很乐意证明是错误的: - )

答案 8 :(得分:0)

两个步骤:

  1. 使用set_bit= x & -x; x&= x - 1;

  2. 提取每个设置位
  3. 减去1并计算位数。

答案 9 :(得分:0)

我认为这会有所帮助

import java.util.*;
public class bitSet {

    public static void main(String[]args) {
        Scanner scnr = new Scanner(System.in);
        int x = scnr.nextInt();
        int i = 0;
        while (i<32) {
            if ( ((x>>i)&1) == 1) {
                System.out.println(i);
            }
            i++;
        }
    }
}