How do you randomly zero a bit in an integer?

后端 未结 13 1913
無奈伤痛
無奈伤痛 2021-02-05 10:11

Updated with newer answer and better test

Let\'s say I have the number 382 which is 101111110.

How could I randomly turn a bit which is not 0 to

相关标签:
13条回答
  • 2021-02-05 10:36

    Count all the 1's in your integer. Choose a random number using your favorite random number generator between 1 and the first count. Create a mask for Random-th 1 in your integer. OR your integer with the mask.

    0 讨论(0)
  • 2021-02-05 10:36

    Try the following code

    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;
    }
    
    0 讨论(0)
  • 2021-02-05 10:38

    OK:

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

    But I would love to know: Why do you need/want this?

    0 讨论(0)
  • 2021-02-05 10:42

    EDIT : fixed to take into account the constraint "a bit which is not 0"

    Pick a random number N between 0 and 31 (for a 32 bit integer), and use it to generate a bitmask by shifting 1 N times to the left. Repeat until bit N is not 0 in the original number. Negate the bitmask to have only 1 bit set to 0 and combine it with your original number with the & operator :

    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;
    }
    
    0 讨论(0)
  • 2021-02-05 10:42

    EDIT: Fixed some logic.

    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;
    
    0 讨论(0)
  • 2021-02-05 10:44

    You can generalize this by using 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;
    }
    

    However then you will have to write helper functions for simple data types.

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

    If your using a large bit array you could save memory by iterating twice.

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

    Test Program.

    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();
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题