Updated with newer answer and better test
更新的答案和更好的测试。
Let's say I have the number 382 which is 101111110.
假设有数字382是101111110。
How could I randomly turn a bit which is not 0 to 0?
我怎么能随机地把位从0转到0呢?
The why;
为什么;
Since people ask me why, I simply need to do this, removing a bit from an integer.
既然人们问我为什么,我只需要这样做,从整数中删除一点。
based on the answer here is the result(working one)
I ran this
根据这里的答案,我运行了这个结果
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));
}
}
}
result;
结果;
Perturb 0.1704681 seconds for 382
Perturb 0.9307034 seconds for 256
Perturb 0.932266 seconds for 1
Perturb 0.4896138 seconds for 257
Perturb 0.1541828 seconds for 999
Perturb 0.2222421 seconds for 555
Perturb 0.2370868 seconds for 412
Perturb 0.2229154 seconds for 341
Perturb 0.2233445 seconds for 682
Perturb 0.1554396 seconds for 951
FastPerturb 0.2988974 seconds for 382
FastPerturb 1.8008209 seconds for 256
FastPerturb 1.7966043 seconds for 1
FastPerturb 0.9255025 seconds for 257
FastPerturb 0.2708695 seconds for 999
FastPerturb 0.4036553 seconds for 555
FastPerturb 0.401872 seconds for 412
FastPerturb 0.4042984 seconds for 341
FastPerturb 0.4028209 seconds for 682
FastPerturb 0.2688467 seconds for 951
SetRandomTrueBitToFalse 0.6127648 seconds for 382
SetRandomTrueBitToFalse 0.4432519 seconds for 256
SetRandomTrueBitToFalse 0.4193295 seconds for 1
SetRandomTrueBitToFalse 0.4543657 seconds for 257
SetRandomTrueBitToFalse 0.6270696 seconds for 999
SetRandomTrueBitToFalse 0.5891294 seconds for 555
SetRandomTrueBitToFalse 0.5910375 seconds for 412
SetRandomTrueBitToFalse 0.6104247 seconds for 341
SetRandomTrueBitToFalse 0.6249519 seconds for 682
SetRandomTrueBitToFalse 0.6142904 seconds for 951
flipRandomBit 0.1624584 seconds for 382
flipRandomBit 0.1284565 seconds for 256
flipRandomBit 0.13208 seconds for 1
flipRandomBit 0.1383649 seconds for 257
flipRandomBit 0.1658636 seconds for 999
flipRandomBit 0.1563506 seconds for 555
flipRandomBit 0.1588513 seconds for 412
flipRandomBit 0.1561841 seconds for 341
flipRandomBit 0.1562256 seconds for 682
flipRandomBit 0.167605 seconds for 951
oneBitsIndexes 2.1871352 seconds for 382
oneBitsIndexes 1.8677352 seconds for 256
oneBitsIndexes 1.8389871 seconds for 1
oneBitsIndexes 1.8729746 seconds for 257
oneBitsIndexes 2.1821771 seconds for 999
oneBitsIndexes 2.1300304 seconds for 555
oneBitsIndexes 2.1098191 seconds for 412
oneBitsIndexes 2.0836421 seconds for 341
oneBitsIndexes 2.0803612 seconds for 682
oneBitsIndexes 2.1684378 seconds for 951
ClearOneBit 0.3005068 seconds for 382
ClearOneBit 1.7872318 seconds for 256
ClearOneBit 1.7902597 seconds for 1
ClearOneBit 0.9243212 seconds for 257
ClearOneBit 0.2666008 seconds for 999
ClearOneBit 0.3929297 seconds for 555
ClearOneBit 0.3964557 seconds for 412
ClearOneBit 0.3945432 seconds for 341
ClearOneBit 0.3936286 seconds for 682
ClearOneBit 0.2686803 seconds for 951
FlipRandomTrueBit 1.5828644 seconds for 382
FlipRandomTrueBit 1.3162437 seconds for 256
FlipRandomTrueBit 1.2944724 seconds for 1
FlipRandomTrueBit 1.3305612 seconds for 257
FlipRandomTrueBit 1.5845461 seconds for 999
FlipRandomTrueBit 1.5252726 seconds for 555
FlipRandomTrueBit 1.5786568 seconds for 412
FlipRandomTrueBit 1.5314749 seconds for 341
FlipRandomTrueBit 1.5311035 seconds for 682
FlipRandomTrueBit 1.6164142 seconds for 951
ClearRandomBit 0.2681578 seconds for 382
ClearRandomBit 0.2728117 seconds for 256
ClearRandomBit 0.2685423 seconds for 1
ClearRandomBit 0.2626029 seconds for 257
ClearRandomBit 0.2623253 seconds for 999
ClearRandomBit 0.274382 seconds for 555
ClearRandomBit 0.2644288 seconds for 412
ClearRandomBit 0.2667171 seconds for 341
ClearRandomBit 0.264912 seconds for 682
ClearRandomBit 0.2666491 seconds for 951扰乱0.1704681秒382扰乱0.9307034秒256扰乱0.932266秒257扰乱扰乱0.4896138秒0.1541828秒999扰乱0.2222421秒555扰乱0.2370868秒412扰乱0.2229154秒341扰乱0.2233445秒682扰乱0.1554396秒951 FastPerturb 0.2988974秒382 FastPerturb 1.8008209秒256 FastPerturb 1.7966043秒257 FastPerturb FastPerturb 0.9255025秒999年0.2708695秒FastPerturb 0.4036553秒555 FastPerturb 0.401872秒412 FastPerturb 0.4042984秒341 FastPerturb 0.4028209秒682 FastPerturb 0.2688467秒951 SetRandomTrueBitToFalse 0.6127648秒382 SetRandomTrueBitToFalse 0.4432519秒256 SetRandomTrueBitToFalse SetRandomTrueBitToFalse 0.4543657秒0.4193295秒257 SetRandomTrueBitToFalse 999 SetRandomTrueBitToFalse 0.5891294 0.6270696秒秒555 SetRandomTrueBitToFalse 0.5910375秒412 SetRandomTrueBitToFalse 0.6104247秒341 SetRandomTrueBitToFalse 0.6249519秒682 SetRandomTrueBitToFalse 0.6142904秒951 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秒412flipRandomBit 0.1561841秒341 flipRandomBit 0.1562256秒682 flipRandomBit 0.167605秒951 oneBitsIndexes 2.1871352秒382 oneBitsIndexes 1.8677352秒256 oneBitsIndexes 1.8389871秒257 oneBitsIndexes oneBitsIndexes 1.8729746秒2.1821771秒999 oneBitsIndexes 2.1300304秒555 oneBitsIndexes 2.1098191秒412 oneBitsIndexes 2.0836421秒341 682 oneBitsIndexes oneBitsIndexes 2.0803612秒951年2.1684378秒ClearOneBit 0.3005068秒382 ClearOneBit 1.7872318秒256 ClearOneBit 1.7902597秒257 ClearOneBit ClearOneBit 0.9243212秒0.2666008秒999 ClearOneBit 0.3929297秒555 ClearOneBit 0.3964557秒412 ClearOneBit 0.3945432秒341 ClearOneBit 0.3936286秒682 ClearOneBit 0.2686803秒951 FlipRandomTrueBit 1.5828644秒382 FlipRandomTrueBit 1.3162437秒256FlipRandomTrueBit 1.2944724秒257 FlipRandomTrueBit FlipRandomTrueBit 1.3305612秒1.5845461秒999 FlipRandomTrueBit 1.5252726秒555 FlipRandomTrueBit 1.5786568秒412 FlipRandomTrueBit 1.5314749秒341 FlipRandomTrueBit 1.5311035秒682 FlipRandomTrueBit 1.6164142秒951 ClearRandomBit 0.2681578秒382 ClearRandomBit 0.2728117秒为1 ClearRandomBit 0.2626029 256 ClearRandomBit 0.2685423秒257 ClearRandomBit 0.2623253秒,999 ClearRandomBit 0.274382秒,555 ClearRandomBit 0.2644288秒,412 ClearRandomBit 0.2667171秒,341 ClearRandomBit 0.264912秒,682 ClearRandomBit 0.2666491秒,951
so in the end, Kyteland is now the winner.
最终,Kyteland成为赢家。
13 个解决方案
#1
14
Here's a slightly more efficient version using 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
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;
}
Update: added code above which can be used for more-bounded performance guarantees (or less unbounded if you want to think of it that way). Interestingly enough this performs better than the original uncommented version.
更新:上面添加的代码可以用于更有限制的性能保证(如果您希望这样考虑的话,可以使用更少的*)。有趣的是,它的性能比最初的未注释版本要好。
Below is an alternate approach that is fast but without bounded performance guarantees:
下面是另一种快速但没有性能保证的方法:
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;
}
#3
4
EDIT : fixed to take into account the constraint "a bit which is not 0"
编辑:固定考虑约束“位不为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 :
在0和31之间选择一个随机数N(对于32位整数),并通过向左移动1 N次来生成一个位掩码。重复,直到第N位在原始数字中不为0。将位掩码设为1位,并将其与原始数字与&操作符结合:
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;
}
#4
4
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?
但是我很想知道:为什么你需要/想要这个?
#5
3
You can turn on any bit by OR'ing it with 1 and turn it off by AND'ing with the bitwise complement.
你可以用1来开启它或者用1来开启它然后用位补来关闭它。
Here's an example that selects a random 1-bit and turns it off.
这里有一个例子,选择一个随机的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...
#6
1
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();
}
}
}
#7
0
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.
数一数整数中的所有1。选择一个随机数,使用您最喜欢的随机数生成器在1和第一个计数之间。为整数中的随机数1创建一个掩码。或者用掩码表示的整数。
#8
0
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;
#9
0
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;
}
#10
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;
}
#11
0
Ok, a lot of wrong answers. Here's one that works:
有很多错误的答案。这是一个工作:
- determine which bit to flip. Do this randomly. I won't supply the code, it's pretty straightforward.
- 确定要翻转哪个位。这样做随机。我不提供代码,这很简单。
- setup a bitmask with all zeros, with a 1 for the bit in question. So for example, if it's the 3rd bit, your bitmask might be 00000100. Again, this doesn't require code.
- 设置一个所有0的位掩码,对于有问题的位设置一个1。例如,如果是第3位,位掩码可能是00000100。同样,这并不需要代码。
- bitwise XOR your number with the bit mask. If you're unfamiliar with the operator it's the hat operator:
^
- 位掩码的位XOR数字。如果你不熟悉运营商的帽子接线员:^
Here's some sample code:
这里有一些示例代码:
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;
Edit: On a fifth read of the question, I have a question in return: you are wanting to do which of the following:
编辑:在第五次阅读这个问题时,我有一个问题要回答:你想做以下哪一个:
- Randomly zero a bit, but only if that bit is already 1. In other words, if the bit in question isn't already 1, the operation is a no-op.
- 随机取0位,但前提是这个位已经是1。换句话说,如果所讨论的位不是1,那么操作将是一个禁止操作。
- Randomly choose a bit that is 1 and zero it. This operation always chooses a bit that is already 1 and always zeros it. The operation is only a no-op if the original value is 0.
- 随机选择一个为1且为0的位。这个操作总是选择一个已经为1的位,并且总是0。只有当初始值为0时,操作才为无操作。
Edit 2:
编辑2:
2 is correct,(15chars) – Fredou
2是正确的,(15chars) - Fredou
In that case, my general algorithm stands; merely choose the bit in step 1 with internal logic. Alternatively, choose a fully random bit in step 1 and repeat until the value of myInt and randomlyZeroedBitInt are not equal.
在这种情况下,我的一般算法成立;只需使用内部逻辑选择步骤1中的位。或者,在步骤1中选择一个完全随机的位并重复,直到myInt和randomlyZeroedBitInt的值不相等。
Unfortunately either case means a more complex algorithm, as you'll either need to iterate over every bit in your value to determine which to flip, or you'll need to loop the algorithm until a bit is flipped.
不幸的是,这两种情况都意味着更复杂的算法,因为您要么需要遍历值中的每一个位,以确定要翻转哪个位,要么需要循环算法,直到有一个位被翻转。
#12
0
Here is a version based on an algorithm from Bit Twiddling Hacks to select the nth set bit of an integer. For this case, we simply select n at random.
这是一个基于Bit twitthacks的算法来选择整数的第n组位的版本。对于这种情况,我们只是随机选择n。
The code has been ported to C#, made to work directly on 32-bit signed integers, and count from the right instead of the left. Furthermore, the optimization to remove all branches has not been preserved here as it yielded slower code on my machine (Intel Core 2 Quad Q9450).
代码已经被移植到c#,直接在32位有符号整数上工作,从右边而不是左边计数。此外,删除所有分支的优化在这里没有被保留,因为它在我的机器上生成了较慢的代码(Intel Core 2 Quad Q9450)。
The description on the Bit Twiddling Hacks page does not give much insight into how the algorithm works. I have taken the time to step through and reverse engineer it and what I found is described in detail in the comments below.
对Bit twitthacks Hacks的hack页面的描述并不能深入了解算法是如何工作的。我花了一些时间来对它进行反向工程,我的发现在下面的评论中有详细的描述。
In my tests, this algorithm performs very similarly to Kyteland's excellent flipRandomBit over input that is distributed randomly across the full range of 32-bit integers. However, flipRandomBit is slightly faster for numbers with significantly fewer set bits than cleared bits. Conversely, this algorithm is slightly faster for numbers with significantly more set bits than cleared bits.
在我的测试中,该算法的性能与Kyteland的优秀flipRandomBit非常相似,它在32位整数的全范围内随机分布。然而,flipRandomBit对于设置位比清除位要少得多的数字来说稍微快一点。相反,对于设置位比清除位大得多的数字,这种算法稍微快一些。
The OP's benchmark consists entirely of small positive integers, which do not stress flipRandomBit's worst case. If this is an indication of the expected input, then all the more reason to prefer 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);
}
#13
-1
int val=382
int mask = ~(1 << N)
// this would turn-off nth bit (0 to 31)
NewVal = (int) ((uint)val & (uint)mask}
#1
14
Here's a slightly more efficient version using 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
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;
}
Update: added code above which can be used for more-bounded performance guarantees (or less unbounded if you want to think of it that way). Interestingly enough this performs better than the original uncommented version.
更新:上面添加的代码可以用于更有限制的性能保证(如果您希望这样考虑的话,可以使用更少的*)。有趣的是,它的性能比最初的未注释版本要好。
Below is an alternate approach that is fast but without bounded performance guarantees:
下面是另一种快速但没有性能保证的方法:
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;
}
#3
4
EDIT : fixed to take into account the constraint "a bit which is not 0"
编辑:固定考虑约束“位不为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 :
在0和31之间选择一个随机数N(对于32位整数),并通过向左移动1 N次来生成一个位掩码。重复,直到第N位在原始数字中不为0。将位掩码设为1位,并将其与原始数字与&操作符结合:
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;
}
#4
4
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?
但是我很想知道:为什么你需要/想要这个?
#5
3
You can turn on any bit by OR'ing it with 1 and turn it off by AND'ing with the bitwise complement.
你可以用1来开启它或者用1来开启它然后用位补来关闭它。
Here's an example that selects a random 1-bit and turns it off.
这里有一个例子,选择一个随机的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...
#6
1
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();
}
}
}
#7
0
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.
数一数整数中的所有1。选择一个随机数,使用您最喜欢的随机数生成器在1和第一个计数之间。为整数中的随机数1创建一个掩码。或者用掩码表示的整数。
#8
0
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;
#9
0
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;
}
#10
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;
}
#11
0
Ok, a lot of wrong answers. Here's one that works:
有很多错误的答案。这是一个工作:
- determine which bit to flip. Do this randomly. I won't supply the code, it's pretty straightforward.
- 确定要翻转哪个位。这样做随机。我不提供代码,这很简单。
- setup a bitmask with all zeros, with a 1 for the bit in question. So for example, if it's the 3rd bit, your bitmask might be 00000100. Again, this doesn't require code.
- 设置一个所有0的位掩码,对于有问题的位设置一个1。例如,如果是第3位,位掩码可能是00000100。同样,这并不需要代码。
- bitwise XOR your number with the bit mask. If you're unfamiliar with the operator it's the hat operator:
^
- 位掩码的位XOR数字。如果你不熟悉运营商的帽子接线员:^
Here's some sample code:
这里有一些示例代码:
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;
Edit: On a fifth read of the question, I have a question in return: you are wanting to do which of the following:
编辑:在第五次阅读这个问题时,我有一个问题要回答:你想做以下哪一个:
- Randomly zero a bit, but only if that bit is already 1. In other words, if the bit in question isn't already 1, the operation is a no-op.
- 随机取0位,但前提是这个位已经是1。换句话说,如果所讨论的位不是1,那么操作将是一个禁止操作。
- Randomly choose a bit that is 1 and zero it. This operation always chooses a bit that is already 1 and always zeros it. The operation is only a no-op if the original value is 0.
- 随机选择一个为1且为0的位。这个操作总是选择一个已经为1的位,并且总是0。只有当初始值为0时,操作才为无操作。
Edit 2:
编辑2:
2 is correct,(15chars) – Fredou
2是正确的,(15chars) - Fredou
In that case, my general algorithm stands; merely choose the bit in step 1 with internal logic. Alternatively, choose a fully random bit in step 1 and repeat until the value of myInt and randomlyZeroedBitInt are not equal.
在这种情况下,我的一般算法成立;只需使用内部逻辑选择步骤1中的位。或者,在步骤1中选择一个完全随机的位并重复,直到myInt和randomlyZeroedBitInt的值不相等。
Unfortunately either case means a more complex algorithm, as you'll either need to iterate over every bit in your value to determine which to flip, or you'll need to loop the algorithm until a bit is flipped.
不幸的是,这两种情况都意味着更复杂的算法,因为您要么需要遍历值中的每一个位,以确定要翻转哪个位,要么需要循环算法,直到有一个位被翻转。
#12
0
Here is a version based on an algorithm from Bit Twiddling Hacks to select the nth set bit of an integer. For this case, we simply select n at random.
这是一个基于Bit twitthacks的算法来选择整数的第n组位的版本。对于这种情况,我们只是随机选择n。
The code has been ported to C#, made to work directly on 32-bit signed integers, and count from the right instead of the left. Furthermore, the optimization to remove all branches has not been preserved here as it yielded slower code on my machine (Intel Core 2 Quad Q9450).
代码已经被移植到c#,直接在32位有符号整数上工作,从右边而不是左边计数。此外,删除所有分支的优化在这里没有被保留,因为它在我的机器上生成了较慢的代码(Intel Core 2 Quad Q9450)。
The description on the Bit Twiddling Hacks page does not give much insight into how the algorithm works. I have taken the time to step through and reverse engineer it and what I found is described in detail in the comments below.
对Bit twitthacks Hacks的hack页面的描述并不能深入了解算法是如何工作的。我花了一些时间来对它进行反向工程,我的发现在下面的评论中有详细的描述。
In my tests, this algorithm performs very similarly to Kyteland's excellent flipRandomBit over input that is distributed randomly across the full range of 32-bit integers. However, flipRandomBit is slightly faster for numbers with significantly fewer set bits than cleared bits. Conversely, this algorithm is slightly faster for numbers with significantly more set bits than cleared bits.
在我的测试中,该算法的性能与Kyteland的优秀flipRandomBit非常相似,它在32位整数的全范围内随机分布。然而,flipRandomBit对于设置位比清除位要少得多的数字来说稍微快一点。相反,对于设置位比清除位大得多的数字,这种算法稍微快一些。
The OP's benchmark consists entirely of small positive integers, which do not stress flipRandomBit's worst case. If this is an indication of the expected input, then all the more reason to prefer 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);
}
#13
-1
int val=382
int mask = ~(1 << N)
// this would turn-off nth bit (0 to 31)
NewVal = (int) ((uint)val & (uint)mask}