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
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.
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;
}
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?
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;
}
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;
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();
}
}
}