给定一个无符号的int,获得设置位的"索引"的最快方法是什么?

时间:2020-03-05 18:55:02  来源:igfitidea点击:

所以例如0110设置了位1和2,1000设置了位3 1111设置了位0,1,2,3

解决方案

回答

我将其下移并在循环中测试最低有效位。使用32位掩码(或者unsigned int的长度)可以更快地进行测试。

/艾伦

回答

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

回答

最快取决于意思。

如果意思是"编写简单代码",则在.NET中,我们可以使用BitArray类,并将每个位引用为布尔值true / false。

BitArray类

回答

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

回答

@艾伦·温德...

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

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上运行,我所描述的方式都更加有效。

回答

Internet上所有这些小技巧和小技巧的最佳参考

回答

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

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

在我看来,这种方法是合理的,但我很乐意证明自己是错误的:-)

回答

如果它是.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的正确重载。

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

回答

两步:

  • set_bit = x&-x;提取每个设置位。 x&= x-1;
  • 减去1并设置计数位。

回答

我认为这会有所帮助

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++;
        }
    }
}