你如何在整数中随机归零?

时间:2010-01-04 19:30:43

标签: c# .net vb.net bit-manipulation

更新了更新的答案和更好的测试

假设我的号码为382,即101111110。

我怎么能随机将一个非0的位转到0?

原因;

由于人们问我为什么,我只需要这样做,从整数中删除一点。

基于这里的答案是结果(工作一个)
我跑了这个

using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Diagnostics;

namespace ConsoleApplication1
{
    class Program
    {
        static Random random;
        static void Main(string[] args)
        {
            Stopwatch sw;
            int[] test = new int[10] { 382, 256, 1, 257, 999, 555, 412, 341, 682, 951 };

            random = new Random(42);
            for (int j = 0; j < 10; j++)
            {
                sw = Stopwatch.StartNew();
                for (int i = 0; i < 1000000; i++)
                    Perturb(test[j]);
                sw.Stop();
                Console.WriteLine("Perturb " + sw.Elapsed.TotalSeconds.ToString("0.#######") + " seconds for " + test[j].ToString());
                Debug.WriteLine("> Perturb " + sw.Elapsed.TotalSeconds.ToString("0.#######") + " seconds for " + test[j].ToString() + "  ");
            }

            random = new Random(42);
            for (int j = 0; j < 10; j++)
            {
                sw = Stopwatch.StartNew();
                for (int i = 0; i < 1000000; i++)
                    FastPerturb(test[j]);
                sw.Stop();
                Console.WriteLine("FastPerturb " + sw.Elapsed.TotalSeconds.ToString("0.#######") + " seconds for " + test[j].ToString());
                Debug.WriteLine("> FastPerturb " + sw.Elapsed.TotalSeconds.ToString("0.#######") + " seconds for " + test[j].ToString() + "  ");
            }

            random = new Random(42);
            for (int j = 0; j < 10; j++)
            {
                sw = Stopwatch.StartNew();
                for (int i = 0; i < 1000000; i++)
                    SetRandomTrueBitToFalse(test[j]);
                sw.Stop();
                Console.WriteLine("SetRandomTrueBitToFalse " + sw.Elapsed.TotalSeconds.ToString("0.#######") + " seconds for " + test[j].ToString());
                Debug.WriteLine("> SetRandomTrueBitToFalse " + sw.Elapsed.TotalSeconds.ToString("0.#######") + " seconds for " + test[j].ToString() + "  ");
            }

            random = new Random(42);
            for (int j = 0; j < 10; j++)
            {
                sw = Stopwatch.StartNew();
                for (int i = 0; i < 1000000; i++)
                    flipRandomBit(test[j]);
                sw.Stop();
                Console.WriteLine("flipRandomBit " + sw.Elapsed.TotalSeconds.ToString("0.#######") + " seconds for " + test[j].ToString());
                Debug.WriteLine("> flipRandomBit " + sw.Elapsed.TotalSeconds.ToString("0.#######") + " seconds for " + test[j].ToString() + "  ");
            }

            random = new Random(42);
            for (int j = 0; j < 10; j++)
            {
                sw = Stopwatch.StartNew();
                for (int i = 0; i < 1000000; i++)
                    oneBitsIndexes(test[j]);
                sw.Stop();
                Console.WriteLine("oneBitsIndexes " + sw.Elapsed.TotalSeconds.ToString("0.#######") + " seconds for " + test[j].ToString());
                Debug.WriteLine("> oneBitsIndexes " + sw.Elapsed.TotalSeconds.ToString("0.#######") + " seconds for " + test[j].ToString() + "  ");
            }

            random = new Random(42);
            for (int j = 0; j < 10; j++)
            {
                sw = Stopwatch.StartNew();
                for (int i = 0; i < 1000000; i++)
                    ClearOneBit(test[j]);
                sw.Stop();
                Console.WriteLine("ClearOneBit " + sw.Elapsed.TotalSeconds.ToString("0.#######") + " seconds for " + test[j].ToString());
                Debug.WriteLine("> ClearOneBit " + sw.Elapsed.TotalSeconds.ToString("0.#######") + " seconds for " + test[j].ToString() + "  ");
            }

            random = new Random(42);
            for (int j = 0; j < 10; j++)
            {
                sw = Stopwatch.StartNew();
                for (int i = 0; i < 1000000; i++)
                    FlipRandomTrueBit(test[j]);
                sw.Stop();
                Console.WriteLine("FlipRandomTrueBit " + sw.Elapsed.TotalSeconds.ToString("0.#######") + " seconds for " + test[j].ToString());
                Debug.WriteLine("> FlipRandomTrueBit " + sw.Elapsed.TotalSeconds.ToString("0.#######") + " seconds for " + test[j].ToString() + "  ");
            }

            random = new Random(42);
            for (int j = 0; j < 10; j++)
            {
                sw = Stopwatch.StartNew();
                for (int i = 0; i < 1000000; i++)
                    ClearRandomBit(test[j]);
                sw.Stop();
                Console.WriteLine("ClearRandomBit " + sw.Elapsed.TotalSeconds.ToString("0.#######") + " seconds for " + test[j].ToString());
                Debug.WriteLine("> ClearRandomBit " + sw.Elapsed.TotalSeconds.ToString("0.#######") + " seconds for " + test[j].ToString() + "  ");
            }

            Console.Read();
        }
        public static int Perturb(int data)
        {
            if (data == 0) return 0;

            int minBits = (data & 0xFFFF0000) == 0 ? 16 : 32;

            int newData = data;
            do
            {
                newData &= ~(1 << random.Next(minBits));
            } while (newData == data);

            return newData;
        }

        public static int FastPerturb(int data)
        {
            if (data == 0) return 0;

            int bit = 0;
            while (0 == (data & (bit = 1 << random.Next(32)))) ;

            return data & ~bit;
        }

        private static Int32 SetRandomTrueBitToFalse(Int32 p)
        {
            List<int> trueBits = new List<int>();
            for (int i = 0; i < 31; i++)
            {
                if ((p >> i & 1) == 1)
                {
                    trueBits.Add(i);
                }
            }
            if (trueBits.Count > 0)
            {
                int index = random.Next(0, trueBits.Count);
                return p & ~(1 << trueBits[index]);
            }
            return p;
        }

        public static int getBitCount(int bits)
        {
            bits = bits - ((bits >> 1) & 0x55555555);
            bits = (bits & 0x33333333) + ((bits >> 2) & 0x33333333);
            return ((bits + (bits >> 4) & 0xF0F0F0F) * 0x1010101) >> 24;
        }

        public static int flipRandomBit(int data)
        {
            int index = random.Next(getBitCount(data));
            int mask = data;

            for (int i = 0; i < index; i++)
                mask &= mask - 1;
            mask ^= mask & (mask - 1);

            return data ^ mask;
        }

        public static int oneBitsIndexes(int data)
        {
            if (data > 0)
            {
                var oneBitsIndexes = Enumerable.Range(0, 31)
                                               .Where(i => ((data >> i) & 0x1) != 0).ToList();
                // pick a random index and update the source value bit there from 1 to 0
                data &= ~(1 << oneBitsIndexes[random.Next(oneBitsIndexes.Count)]);
            }
            return data;
        }

        static private int ClearOneBit(int originalValue)
        {
            if (originalValue == 0)
                return 0; // All bits are already set to 0, nothing to do

            int mask = 0;
            do
            {
                int n = random.Next(32);
                mask = 1 << n;
            } while ((mask & originalValue) == 0); // check that this bit is not 0

            int newValue = originalValue & ~mask; // clear this bit
            return newValue;
        }

        public static BitArray FlipRandomTrueBit(BitArray bits)
        {
            List<int> trueBits = new List<int>();

            for (int i = 0; i < bits.Count; i++)
                if (bits[i])
                    trueBits.Add(i);

            if (trueBits.Count > 0)
            {
                int index = random.Next(0, trueBits.Count);
                bits[trueBits[index]] = false;
            }

            return bits;
        }

        public static int FlipRandomTrueBit(int input)
        {
            BitArray bits = new BitArray(new int[] { input });
            BitArray flipedBits = FlipRandomTrueBit(bits);

            byte[] bytes = new byte[4];
            flipedBits.CopyTo(bytes, 0);

            int result = BitConverter.ToInt32(bytes, 0);
            return result;
        }

        static int ClearRandomBit(int value)
        {
            return unchecked((int)ClearRandomBit((ulong)(uint)value));
        }
        static ulong ClearRandomBit(ulong value)
        {
            // Algorithm from http://graphics.stanford.edu/~seander/bithacks.html
            //
            //   "Select the bit position (from the most-significant bit) with the 
            //   given count (rank)."
            //   
            //   The following 64-bit code selects the position of the rth 1 bit when
            //   counting from the left. In other words if we start at the most 
            //   significant bit and proceed to the right, counting the number of bits
            //   set to 1 until we reach the desired rank, r, then the position where 
            //   we stop will be the final value given to s.

            // Do a normal parallel bit count for a 64-bit integer,                     
            // but store all intermediate steps.
            ulong v = value;
            ulong a = v - ((v >> 1) & ~0UL / 3);
            ulong b = (a & ~0UL / 5) + ((a >> 2) & ~0UL / 5);
            ulong c = (b + (b >> 4)) & ~0UL / 0x11;
            ulong d = (c + (c >> 8)) & ~0UL / 0x101;
            ulong t = (uint)((d >> 32) + (d >> 48));

            // Choose a random r in the range [1-bitCount]
            int bitCount = (int)((d * (~0UL / 255)) >> 56);
            int randomRank = 1 + random.Next(bitCount);
            ulong r = (ulong)randomRank;

            // Compute s                                       
            ulong s = 64;
            s -= ((t - r) & 256UL) >> 3;
            r -= (t & ((t - r) >> 8));
            t = (d >> (int)(s - 16)) & 0xff;
            s -= ((t - r) & 256UL) >> 4;
            r -= (t & ((t - r) >> 8));
            t = (c >> (int)(s - 8)) & 0xf;
            s -= ((t - r) & 256UL) >> 5;
            r -= (t & ((t - r) >> 8));
            t = (b >> (int)(s - 4)) & 0xf;
            s -= ((t - r) & 256UL) >> 6;
            r -= (t & ((t - r) >> 8));
            t = (a >> (int)(s - 2)) & 0x3;
            s -= ((t - r) & 256UL) >> 7;
            r -= (t & ((t - r) >> 8));
            t = (v >> (int)(s - 1)) & 0x1;
            s -= ((t - r) & 256UL) >> 8;
            s = 65 - s;

            // Clear the selected bit
            return value & ~(1UL << (int)(64 - s));
        }
    }
}

结果;

  

382的Perturb 0.1704681秒   Perturb 0.9307034秒为256
  Perturb为0.932266秒为1   扰动0.4896138秒为257
  999的Perturb 0.1541828秒   555的Perturb 0.2222421秒   对于412
,Perturb 0.2370868秒   对于341
,Perturb 0.2229154秒   682的Perturb 0.2233445秒   951的Perturb 0.1554396秒   FastPerturb 0.2988974秒为382
  FastPerturb 1.8008209秒为256
  FastPerturb 1.7966043秒为1
  FastPerturb 0.9255025秒为257
  FastPerturb为0.2998695秒为999
  FastPerturb 0.4036553秒为555
  快速扰动0.401872秒为412
  快速扰动0.4042984秒为341
  FastPerturb为0.4828209秒为682
  951的FastPerturb 0.2688467秒   对于382
,SetRandomTrueBitToFalse为0.6127648秒   对于256
,SetRandomTrueBitToFalse为0.4432519秒   对于1
,SetRandomTrueBitToFalse为0.4193295秒   SetRandomTrueBitToFalse 0.4543657秒为257
  SetRandomTrueBitToFalse为0.9970696秒为999
  555的SetRandomTrueBitToFalse 0.5891294秒   对于412
,SetRandomTrueBitToFalse 0.5910375秒   对于341
,SetRandomTrueBitToFalse为0.6104247秒   SetRandomTrueBitToFalse 0.6249519秒为682
  951的SetRandomTrueBitToFalse 0.6142904秒   flipRandomBit 0.1624584秒为382
  flipRandomBit 0.1284565秒为256
  flipRandomBit 0.13208秒为1
  flipRandomBit 0.1383649秒为257
  flipRandomBit 0.1658636秒为999
  flipRandomBit 0.1563506秒为555
  flipRandomBit 0.1588513秒为412
  flipRandomBit 0.1561841秒为341
  flipRandomBit 0.1562256秒为682
  flipRandomBit 0.167605秒为951
  oneBitsIndexes为2月28871352秒   oneBitsIndexes为25686的1.8677352秒   oneBitsIndexes 1.8389871秒为1
  oneBitsIndexes为1887年的1.8729746秒   oneBitsIndexes为999的2.1821771秒   oneBitsIndexes为21500的2.1300304秒   412B的oneBitsIndexes 2.1098191秒   341B的oneBitsIndexes 2.0836421秒   oneBitsIndexes为682的2.0803612秒   oneBitsIndexes为951的2.1684378秒   ClearOneBit 0.3005068秒为382
  ClearOneBit 1.7872318秒为256
  ClearOneBit 1.7902597秒为1
  ClearOneBit 0.9243212秒为257
  ClearOneBit 0.2666008秒为999
  555的ClearOneBit 0.3929297秒   412的ClearOneBit 0.3964557秒   341O的ClearOneBit 0.3945432秒   4月份ClearOneBit 0.3936286秒   951的ClearOneBit为0.2686803秒   FlipRandomTrueBit 1.5828644秒为382
  FlipRandomTrueBit为25616的1.3162437秒   FlipRandomTrueBit 1.2944724秒为1
  FlipRandomTrueBit 1.3305612秒为257
  FlipRandomTrueBit 1.5845461秒为999
  FlipRandomTrueBit 1.5252726秒为555
  对于412
,FlipRandomTrueBit 1.5786568秒   对于341
,FlipRandomTrueBit 1.5314749秒   FlipRandomTrueBit 1.5311035秒为682
  951的FlipRandomTrueBit 1.6164142秒   ClearRandomBit 0.2681578秒为382
  ClearRandomBit为0.2728117秒为256
  ClearRandomBit为1周的0.2685423秒   257的ClearRandomBit 0.2626029秒   ClearRandomBit 0.2623253秒为999
  ClearRandomBit 0.274382秒为555
  对于412
,ClearRandomBit为0.2644288秒   对于341
,ClearRandomBit为0.2667171秒   4,6的ClearRandomBit 0.264912秒   957的ClearRandomBit 0.2666491秒

所以最后,Kyteland现在是赢家。

13 个答案:

答案 0 :(得分:15)

static Random random = new Random();

public static int Perturb(int data)
{
    if (data == 0) return 0;

    // attempt to pick a more narrow search space
    int minBits = (data & 0xFFFF0000) == 0 ? 16 : 32;

    // int used = 0; // Uncomment for more-bounded performance
    int newData = data;
    do
    {
        // Unbounded performance guarantees
        newData &= ~(1 << random.Next(minBits));

        // // More-bounded performance:
        // int bit = 1 << random.Next(minBits);
        // if ((used & bit) == bit) continue;
        // used |= bit;
        // newData &= ~bit;
    } while (newData == data); // XXX: we know we've inverted at least one 1
                               // when the new value differs

    return newData;
}

更新:添加的代码可用于更有限的性能保证(如果您想以这种方式考虑,则可以使用更少的无限制)。有趣的是,这比原始的未注释版本表现更好。

下面是一种快速但没有有限性能保证的替代方法:

public static int FastPerturb(int data)
{
    if (data == 0) return 0;

    int bit = 0;
    while (0 == (data & (bit = 1 << random.Next(32))));

    return data & ~bit;
}

答案 1 :(得分:14)

这是一个使用bit twiddling的更高效的版本。

    public static int getBitCount(int bits)
    {
        bits = bits - ((bits >> 1) & 0x55555555);
        bits = (bits & 0x33333333) + ((bits >> 2) & 0x33333333);
        return ((bits + (bits >> 4) & 0xF0F0F0F) * 0x1010101) >> 24;
    }

    public static int flipRandomBit(int data)
    {
        int index = random.Next(getBitCount(data));
        int mask = data;

        for (int i = 0; i < index; i++)
            mask &= mask - 1;
        mask ^= mask & (mask - 1);

        return data ^ mask;
    }

答案 2 :(得分:4)

编辑:修复以考虑约束“有点不是0”

选择0到31之间的随机数N(对于32位整数),并使用它通过向左移动1 N次来生成位掩码。重复,直到原始编号中的位N不为0。将位掩码取消为仅将1位设置为0,并将其与原始数字组合使用&amp;运营商:

private int ClearOneBit(int originalValue)
{
    if (originalValue == 0)
        return 0; // All bits are already set to 0, nothing to do

    Random rnd = new Random();
    int mask = 0;
    do
    {
        int n = rnd.Next(32);
        mask = 1 << n;
    } while ((mask & originalValue) == 0); // check that this bit is not 0

    int newValue = originalValue & ~mask; // clear this bit
    return newValue;
}

答案 3 :(得分:4)

行:

    private static Random rnd = new Random((int)DateTime.Now.Ticks);

    private static Int32 SetRandomTrueBitToFalse(Int32 p)
    {
        List<int> trueBits = new List<int>();
        for (int i = 0; i < 31; i++)
        {
            if ((p>>i&1) == 1){
                trueBits.Add(i);
            }
        }
        if (trueBits.Count>0){
            int index = rnd.Next(0, trueBits.Count);
            return p & ~(1 << trueBits[index]);
        }
        return p;
    }

但我很想知道:你为什么需要/想要这个?

答案 4 :(得分:3)

你可以通过将其与1进行“或”来打开任何位,然后通过使用按位补码进行“与”来关闭它。

这是一个选择随机1位并将其关闭的示例。

var rand = new Random();
int myValue = 0x017E; // 101111110b
// identify which indexes are one-bits (if any, thanks Doc)
if( myValue > 0 )
{
    var oneBitsIndexes = Enumerable.Range( 0, 31 )
                                   .Where(i => ((myValue >> i) & 0x1) !=0).ToList();
    // pick a random index and update the source value bit there from 1 to 0
    myValue &= ~(1 << oneBitsIndexes[rand.Next(oneBitsIndexes.Count)]);
}
// otherwise, there are no bits to turn off...

答案 5 :(得分:1)

您可以使用BitArray来概括它。

public static BitArray FlipRandomTrueBit(BitArray bits)
{
    List<int> trueBits = new List<int>();

    for (int i = 0; i < bits.Count; i++)
        if (bits[i])
            trueBits.Add(i);

    if (trueBits.Count > 0)
    {
        int index = rnd.Next(0, trueBits.Count);
        bits[trueBits[index]] = false;
    }

    return bits;
}

然而,您必须为简单数据类型编写辅助函数。

public static int FlipRandomTrueBit(int input)
{
    BitArray bits = new BitArray(new int[] { input });
    BitArray flipedBits = FlipRandomTrueBit(bits);

    byte[] bytes = new byte[4];
    flipedBits.CopyTo(bytes, 0);

    int result = BitConverter.ToInt32(bytes, 0);
    return result;
}

如果使用大位数组,可以通过迭代两次来节省内存。

public static void FlipRandomTrueBitLowMem(ref BitArray bits)
{
    int trueBits = 0;

    for (int i = 0; i < bits.Count; i++)
        if (bits[i])
            trueBits++;

    if (trueBits > 0)
    {
        int flip = rnd.Next(0, trueBits);

        for (int i = 0; i < bits.Count; i++)
        {
            if (bits[i])
            {
                if (flip == 0)
                {
                    bits[i] = false;
                    break;
                }

                flip--;
            }
        }
    }
}

测试计划。

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace bitarray
{
    class Program
    {
        private static Random rnd = new Random((int)DateTime.Now.Ticks);

        public static BitArray FlipRandomTrueBit(BitArray bits)
        {
            List<int> trueBits = new List<int>();

            for (int i = 0; i < bits.Count; i++)
                if (bits[i])
                    trueBits.Add(i);

            if (trueBits.Count > 0)
            {
                int index = rnd.Next(0, trueBits.Count);
                bits[trueBits[index]] = false;
            }

            return bits;
        }

        public static int FlipRandomTrueBit(int input)
        {
            BitArray bits = new BitArray(new int[] { input });
            BitArray flipedBits = FlipRandomTrueBit(bits);

            byte[] bytes = new byte[4];
            flipedBits.CopyTo(bytes, 0);

            int result = BitConverter.ToInt32(bytes, 0);
            return result;
        }

        static void Main(string[] args)
        {
            int test = 382;
            for (int n = 0; n < 200; n++)
            {
                int result = FlipRandomTrueBit(test);
                Console.WriteLine(result);
            }

            Console.ReadLine();
        }
    }
}

答案 6 :(得分:0)

尝试以下代码

public static int ChangeOneBit(int data)
{
    if (data == 0)
    {
        return data;
    }

    var random = new Random();
    int bit = 0;
    do
    {
        var shift = random.Next(31);
        bit = data >> shift;
        bit = bit & 0x00000001;
    } while (bit == 0);
    var ret = data & (~(1 << bit));
    return ret;
}

答案 7 :(得分:0)

编辑:修正了一些逻辑。

BitArray bits = new BitArray(new int[] { number } );

randomIndex = new Random().Next(32);

// check if bit is true, if not, goes to next bit and wraps around as well.
for(int i = 0; i < 32; i++)
{
    if(bits[randomIndex] == false)
    {
    randomIndex = (randomIndex + 1) % 32;
    }
    else
    {
        break;
    }
}

bits[randomIndex] = false;

答案 8 :(得分:0)

计算整数中的所有1。 使用您最喜欢的随机数生成器在1和第一个计数之间选择一个随机数。 在整数中为Random-th 1创建一个掩码。 或者你的整数与掩码。

答案 9 :(得分:0)

int changeBit(int a)
{
    a = ~a;
    int temp = a;
    while(temp == a)
    {
        r = Math.pow(2,(int)(32*random.next()));
        a = a || r;    
    }

    return ~a;
}

答案 10 :(得分:0)

好的,很多错误的答案。这是一个有效的方法:

  1. 确定要翻转的位。随机做这个。我不会提供代码,这非常简单。
  2. 设置一个全零的位掩码,对于该位有一个1。因此,例如,如果它是第3位,则您的位掩码可能是00000100。同样,这不需要代码。
  3. 按比特XOR使用位掩码编号。如果您不熟悉操作员,那就是帽子操作员:^
  4. 以下是一些示例代码:

    int myInt; // set this up with your original value
    int myBitmask; // set this up with the bit mask via steps 1 and 2.
    int randomlyZeroedBitInt = myInt ^ myBitmask;
    

    编辑:在第五次阅读问题时,我有一个问题作为回报:您想要做以下哪项:

    1. 随机归零,但仅当该位已经为1.换句话说,如果有问题的位不是1,则操作为无操作。
    2. 随机选择1和0的位。此操作始终选择一个已经为1的位并始终将其置零。如果原始值为0,则该操作仅为无操作。
    3. 编辑2:

        

      2是正确的,(15chars) - Fredou

      在这种情况下,我的通用算法代表;仅使用内部逻辑选择步骤1中的位。或者,在步骤1中选择一个完全随机的位并重复,直到myInt和randomZeroedBitInt的值不相等。

      不幸的是,任何一种情况都意味着更复杂的算法,因为您需要迭代值中的每一位以确定要翻转的位,或者您需要循环算法直到翻转一位。

答案 11 :(得分:0)

这是一个基于algorithm Bit Twiddling Hacks的版本,用于选择整数的第n个设置位。对于这种情况,我们只需随机选择n。

代码已移植到C#,直接在32位有符号整数上工作,并从右边而不是左边开始计数。此外,删除所有分支的优化还没有在这里保留,因为它在我的机器上产生了较慢的代码(英特尔酷睿2四核Q9450)。

Bit Twiddling Hacks页面上的描述没有深入了解算法的工作原理。我花时间逐步完成并对其进行逆向工程,我在下面的评论中详细描述了我发现的内容。

在我的测试中,这个算法的表现与Kyteland优秀的flipRandomBit相比,在整个32位整数范围内随机分布。但是,对于设置位明显少于清除位的数字,flipRandomBit稍快一些。相反,对于设置位明显多于清零位的数字,此算法稍快一些。

OP的基准完全由小正整数组成,不会强调flipRandomBit的最坏情况。如果这是预期输入的指示,则更有理由更喜欢flipRandomBit。

static int ClearRandomSetBit(int input) {
    ///////////////////////////////////////////////////////////////////////
    // ** Step 1 **
    // Count the set bits
    ////////////////////////////////////////////////////////////////////////

    // magic numbers
    const int m2 = 0x55555555; // 1 zero,  1 one,  ...
    const int m4 = 0x33333333; // 2 zeros, 2 ones, ...
    const int m8 = 0x0f0f0f0f; // 4 zeros, 4 ones, ...

    // sequence of 2-bit values representing the counts of each 2 bits.
    int c2 = input - ((input >> 1) & m2);

    // sequence of 4-bit values representing the counts of each 4 bits.
    int c4 = (c2 & m4) + ((c2 >> 2) & m4);

    // sequence of 8-bit values representing the counts of each 8 bits.
    int c8 = (c4 + (c4 >> 4)) & m8;

    // count set bits in input.
    int bitCount = (c8 * 0x1010101) >> 24;

    ///////////////////////////////////////////////////////////////////////////////////
    // ** Step 2 ** 
    // Select a random set bit to clear and find it using binary search with our 
    // knowledge of the bit counts in the various regions.
    ///////////////////////////////////////////////////////////////////////////////////

    // count 16 right-most bits where we'll begin our search
    int count = (c8 + (c8 >> 8)) & 0xff;

    // position of target bit among the set bits
    int target = random.Next(bitCount);

    // distance in set bits from the current position to the target
    int distance = target + 1;

    // current bit position 
    int pos = 0;

    // if the target is not in the right-most 16 bits, move past them
    if (distance > count) { pos += 16; distance -= count; }

    // if the target is not in the next 8 bits, move past them
    count = (c8 >> pos) & 0xff;
    if (distance > count) { pos += 8; distance -= count; }

    // if the target is not in the next 4 bits, move past them
    count = (c4 >> pos) & 0xf;
    if (distance > count) { pos += 4; distance -= count; }

    // if the target is not in the next 2 bits, move past them
    count = (c2 >> pos) & 0x3;
    if (distance > count) { pos += 2; distance -= count; }

    // if the bit is not the next bit, move past it.
    //
    // Note that distance and count must be single bits by now.
    // As such, distance is greater than count if and only if 
    // distance equals 1 and count equals 0. This obversation
    // allows us to optimize away the final branch.
    Debug.Assert((distance & 0x1) == distance);
    Debug.Assert((count & 0x1) == count);
    count = (input >> pos) & 0x1;
    pos += (distance & (count ^ 1));

    Debug.Assert((input & (1 << pos)) != 0);
    return input ^ (1 << pos);
}

答案 12 :(得分:-1)

 int val=382

 int mask = ~(1 << N)   

 // this would turn-off nth bit (0 to 31)
 NewVal = (int) ((uint)val & (uint)mask} 
相关问题