Reading bit-aligned data - c#

I have been reading the SWF format available on Adobe's site and it mentions that in order to save space, variable bits are used to store integers or floats (page 17 in the pdf)
I have always worked with byte-aligned data so have not given much thought to files that are bit-aligned, or have variable alignment where the information is stored in each byte.
So for example, you may have a struct containing four 13-bit integers stored sequentially ( rather than storing them as four 16-bit integers).
The first 13bits is the first integer, the next 13 bits is the second integer, and so on. It pads the last byte appropriate to make the struct byte-aligned with the rest of the file, so 52-bits would be padded to 56-bits, requiring 7 bytes to store those four integers as opposed to 8 bytes.
How do I approach this kind of problem?
How can I work with a stream of bytes at the bit-level?
Is there something I can use to help make it easier to work with this data?
I imagine the solution boils down to using bit-operations on byte arrays.
An example solution for parsing the four 13-bit integers would be nice as well to demonstrate the use of your suggested method.

There are two ways of dealing with this that I know of. The first is to manually do it - using bit-wise operators, division, modulus etc. on byte arrays [or integer/ulong etc if you were bored]. IsBitSet Example
The other way is a BitArray - which handles most of this for you :)
It would be nice to add an example of how exactly BitArray handles getting bits 13..25 as an int, as that would be the primary operation. At a first glance I see only a loop.
Fine... I wrote a quick & dirty test proof of concept:
var rnd = new Random();
//var data = Enumerable.Range(0, 10).ToArray();
var data = Enumerable.Range(0, 10).Select(x => rnd.Next(1 << 13)).ToArray();
foreach (var n in data) Console.WriteLine(n);
Console.WriteLine(new string('-', 13));
var bits = new BitArray(data.Length * 13);
for (int i = 0; i < data.Length; i++)
{
var intBits = new BitArray(new[] { data[i] });
for (int b = 12; b > -1; b--)
{
bits[i * 13 + b] = intBits[b];
Console.Write(intBits[b] ? 1 : 0);
}
Console.WriteLine();
}
Console.WriteLine(new string('-', 13));
for (int i = 0; i < bits.Length / 13; i++)
{
int number = 0;
for (int b = 12; b > -1; b--)
if (bits[i * 13 + b])
number += 1 << b;
Console.WriteLine(number);
}
Console.ReadLine();
Which outputs:
910
3934
7326
7990
7712
1178
6380
3460
5113
7489
-------------
0001110001110
0111101011110
1110010011110
1111100110110
1111000100000
0010010011010
1100011101100
0110110000100
1001111111001
1110101000001
-------------
910
3934
7326
7990
7712
1178
6380
3460
5113
7489
The bit array doesn't do much other than simplify accessing - it's still quite manual. I expect you'd write your own classes to simply this and make it neat and reusable - for example here's another quick concept:
//Improved to take sign into account.
//Sign is in addition to bits allocated for storage in this version.
//Stored as {sign}{bits}
//E.g. -5, stored in 3 bits signed is:
// 1 101
//E.g. 5, stored in 3 bits [with sign turned on]
// 0 101
//E.g. 5, stored in 3 bits no sign
// 101
//This may differ from your exiting format - e.g. you may use two's compliments.
static void Main(string[] args)
{
int bitsPerInt = 13;
//Create your data
var rnd = new Random();
//var data = Enumerable.Range(-5, 10).ToArray();
var data = Enumerable.Range(0, 10).Select(x => rnd.Next(-(1 << bitsPerInt), 1 << bitsPerInt)).ToArray();
var bits = new BitSerlializer();
//Add length header
bits.AddInt(data.Length, 8, false);
foreach (var n in data)
{
bits.AddInt(n, bitsPerInt);
Console.WriteLine(n);
}
//Serialize to bytes for network transfer etc.
var bytes = bits.ToBytes();
Console.WriteLine(new string('-', 10));
foreach (var b in bytes) Console.WriteLine(Convert.ToString(b, 2).PadLeft(8, '0'));
Console.WriteLine(new string('-', 10));
//Deserialize
bits = new BitSerlializer(bytes);
//Get Length Header
var count = bits.ReadInt(8, false);
for (int i = 0; i < count; i++)
Console.WriteLine(bits.ReadInt(bitsPerInt));
Console.ReadLine();
}
public class BitSerlializer
{
List<byte> bytes;
int Position { get; set; }
public BitSerlializer(byte[] initialData = null)
{
if (initialData == null)
bytes = new List<byte>();
else
bytes = new List<byte>(initialData);
}
public byte[] ToBytes() { return bytes.ToArray(); }
public void Addbit(bool val)
{
if (Position % 8 == 0) bytes.Add(0);
if (val) bytes[Position / 8] += (byte)(128 >> (Position % 8));
Position++;
}
public void AddInt(int i, int length, bool isSigned = true)
{
if (isSigned) Addbit(i < 0);
if (i < 0) i = -i;
for (int pos = --length; pos >= 0; pos--)
{
var val = (i & (1 << pos)) != 0;
Addbit(val);
}
}
public bool ReadBit()
{
var val = (bytes[Position / 8] & (128 >> (Position % 8))) != 0;
++Position;
return val;
}
public int ReadInt(int length, bool isSigned = true)
{
var val = 0;
var sign = isSigned && ReadBit() ? -1 : 1;
for (int pos = --length; pos >= 0; pos--)
if (ReadBit())
val += 1 << pos;
return val * sign;
}
}

On the other hand, byte-array-based approach could go like this:
int extend(uint raw, int bits)
{
int sh = 32 - bits;
int x = (int)raw << sh; // puts your sign bit in the highest bit.
return x >> sh; // since x is signed this is an arithmatic signed shift
}
int read(byte[] data, int pos, int bits, bool signed)
{
int fbi = pos / 8; // first byte index
int lbi = (pos + bits - 1) / 8; // last byte index
int cnt = lbi - fbi + 1; // bytes spanned
if (cnt > 3 || lbi >= data.Length) { throw new ArgumentException(); }
uint raw = (uint)(
(data[fbi] << (24 + pos % 8)) +
(cnt < 2 ? 0 : data[fbi + 1] << (16 + pos % 8)) +
(cnt < 3 ? 0 : data[fbi + 2] << (8 + pos % 8))
) >> (32 - bits);
return signed ? extend(raw, bits) : (int)raw;
}
Test for this:
byte[] test = { 0x55, 0xAA, 0x10 };
string s = "";
s += read(test, 0, 8, false) + "\r\n";
s += read(test, 0, 8, true) + "\r\n";
s += read(test, 8, 8, false) + "\r\n";
s += read(test, 8, 8, true) + "\r\n";
s += read(test, 4, 8, false) + "\r\n";
s += read(test, 7, 9, true) + "\r\n";
s += read(test, 7, 10, true) + "\r\n";
s += read(test, 7, 11, true) + "\r\n";
s += read(test, 7, 12, true) + "\r\n";
s += read(test, 7, 13, true) + "\r\n";
s += read(test, 7, 14, true) + "\r\n";
s += read(test, 7, 15, true) + "\r\n";
s += read(test, 7, 16, true) + "\r\n";
s += read(test, 7, 17, true) + "\r\n";
s += read(test, 18, 2, true) + "\r\n";
s += read(test, 18, 3, true) + "\r\n";
s += read(test, 23, 1, true) + "\r\n";
s += read(test, 23, 2, true) + "\r\n";
The test builds the string like the following:
85
85
170
-86
90
-86
-172
-344
-688
-1375
-2750
-5500
-11000
-22000
1
2
0
then throws an exception on the last line.

Related

Converting 32bit wav array to x-bit

I have a 32 bit wav array and I wanted to convert it to 8 bit
So I tried to take this function which converts 32 to 16
void _waveIn_DataAvailable(object sender, WaveInEventArgs e)
{
byte[] newArray16Bit = new byte[e.BytesRecorded / 2];
short two;
float value;
for (int i = 0, j = 0; i < e.BytesRecorded; i += 4, j += 2)
{
value = (BitConverter.ToSingle(e.Buffer, i));
two = (short)(value * short.MaxValue);
newArray16Bit[j] = (byte)(two & 0xFF);
newArray16Bit[j + 1] = (byte)((two >> 8) & 0xFF);
}
}
And modify it to take x bit as destination
private byte[] Convert32BitRateToNewBitRate(byte[] bytes, int newBitRate)
{
var sourceBitRate = 32;
byte[] newArray = new byte[bytes.Length / (sourceBitRate / newBitRate)];
for (int i = 0, j = 0; i < bytes.Length; i += (sourceBitRate / 8), j += (newBitRate / 8))
{
var value = (BitConverter.ToSingle(bytes, i));
var two = (short)(value * short.MaxValue);
newArray[j] = (byte)(two & 0xFF);
newArray[j + 1] = (byte)((two >> 8) & 0xFF);
}
return newArray;
}
My problem is that I wasn't sure how to convert the code within the "for" loop, I tried to debug it but I couldn't quite figure out how it works.
I saw here : simple wav 16-bit / 8-bit converter source code?, that they divided the value by 256 to get from 16 to 8, I tried to divide by 256 to get from 32 to 16 but it didn't work
for (int i = 0, j = 0; i < bytes.Length; i += sourceBitRateBytes, j += newBitRateBytes)
{
var value = BitConverter.ToInt32(bytes, i);
value /= (int)Math.Pow(256, sourceBitRate / newBitRate / 2.0);
var valueBytes = BitConverter.GetBytes(value);
for (int k = 0; k < newBitRateBytes; k++)
{
newArray[k + j] = valueBytes[k];
}
The for loop is still using 16 bit in the following places:
short.MaxValue. Use byte.MaxValue instead.
by assigning two bytes at [j] and [j+1]. Assign one byte only.
I don't have the rest of the program and no sample data, so it's hard for me to try. But I'd say the following sounds about right
for (int i = 0, j = 0; i < bytes.Length; i += (sourceBitRate / 8), j += (newBitRate / 8))
{
var value = (BitConverter.ToSingle(bytes, i));
var two = (byte)(value * byte.MaxValue);
newArray[j] = two;
}
Be aware that this works for 8 bit only, so newBitRate must be 8, otherwise it does not work. It should probably not be a parameter to the method.

Fastest way to get last significant bit position in a ulong (C#)?

What is the fastest(or at least very fast) way to get first set(1) bit position from least significant bit (LSB) to the most significant bit (MSB) in a ulong (C#)?
For ulong i = 18; (10010) that would be 2(or 1 if we are counting position from 0).
MS C++ compiler has _BitScanForward64 Intrinsics for this task, but C# compiler doesn't have analogue.
With .NET Core 3.0 introducing hardware intrinsics, the fastest solution should be
ulong value = 18;
ulong result = System.Runtime.Intrinsics.X86.Bmi1.X64.TrailingZeroCount(value);
Alternatively, the new System.Numerics.Bitoperations methods also use hardware intrinsics:
int result2 = System.Numerics.BitOperations.TrailingZeroCount(value);
public static UInt64 CountTrailingZeros(UInt64 input)
{
if (input == 0) return 64;
UInt64 n = 0;
if ((input & 0xFFFFFFFF) == 0) { n = 32; input = input >> 32; }
if ((input & 0xFFFF) == 0) { n = n + 16; input = input >> 16; }
if ((input & 0xFF) == 0) { n = n + 8; input = input >> 8; }
if ((input & 0xF) == 0) { n = n + 4; input = input >> 4; }
if ((input & 3) == 0) { n = n + 2; input = input >> 2; }
if ((input & 1) == 0) { ++n; }
return n;
}
I changed the answer of Michael D. O'Connor to match Your question.
I have measured perfomance of all answers.
The winner is not present here classic De Bruijn sequence approach.
private const ulong DeBruijnSequence = 0x37E84A99DAE458F;
private static readonly int[] MultiplyDeBruijnBitPosition =
{
0, 1, 17, 2, 18, 50, 3, 57,
47, 19, 22, 51, 29, 4, 33, 58,
15, 48, 20, 27, 25, 23, 52, 41,
54, 30, 38, 5, 43, 34, 59, 8,
63, 16, 49, 56, 46, 21, 28, 32,
14, 26, 24, 40, 53, 37, 42, 7,
62, 55, 45, 31, 13, 39, 36, 6,
61, 44, 12, 35, 60, 11, 10, 9,
};
/// <summary>
/// Search the mask data from least significant bit (LSB) to the most significant bit (MSB) for a set bit (1)
/// using De Bruijn sequence approach. Warning: Will return zero for b = 0.
/// </summary>
/// <param name="b">Target number.</param>
/// <returns>Zero-based position of LSB (from right to left).</returns>
private static int BitScanForward(ulong b)
{
Debug.Assert(b > 0, "Target number should not be zero");
return MultiplyDeBruijnBitPosition[((ulong)((long)b & -(long)b) * DeBruijnSequence) >> 58];
}
The fastest way is to inject Bit Scan Forward (bsf) Bit Instruction to assembly after JIT compiler instead of BitScanForward body, but this requires much more efforts.
public static UInt64 CountLeadingZeros(UInt64 input)
{
if (input == 0) return 64;
UInt64 n = 1;
if ((input >> 32) == 0) { n = n + 32; input = input << 32; }
if ((input >> 48) == 0) { n = n + 16; input = input << 16; }
if ((input >> 56) == 0) { n = n + 8; input = input << 8; }
if ((input >> 60) == 0) { n = n + 4; input = input << 4; }
if ((input >> 62) == 0) { n = n + 2; input = input << 2; }
n = n - (input >> 63);
return n;
}
I'll bet this'll be faster. From here.
static Int32 GetLSBPosition(UInt64 v) {
UInt64 x = 1;
for (var y = 0; y < 64; y++) {
if ((x & v) == x) {
return y;
}
x = x << 1;
}
return 0;
}
While similar to Alexander's answer, this form performs consistently faster, about 46 million operations per second on my machine.
Also, I have written it to be Zero based, but personally I think it should be 1 based, eg:
Assert.Equal(0, GetLSBPosition(0));
Assert.Equal(1, GetLSBPosition(1));
Assert.Equal(1, GetLSBPosition(3));
As a bit-wise operation, the lowest set bit is:
ulong bit = x & ~(x-1);
and the original value with the lowest on-bit set to off is:
x & (x-1)
So to get all the bits that are on:
public static void Main()
{
ulong x = 13;
while(x > 0)
{
ulong bit = x & ~(x-1);
x = x & (x-1);
Console.WriteLine("bit-value {0} is set", bit);
}
}
Output
bit-value 1 is set
bit-value 4 is set
bit-value 8 is set
The solution with a very fast bit operations. Only unsafe code can be faster.
ulong n = 18; // 10010
ulong b = 1;
int p = 0;
for (int i = 0; i < 64; i++)
{
if ((n & b) == b)
{
p = i;
break;
}
b = b << 1;
}
Console.WriteLine(p);

Try to calculate IP header checksum

i try to write a function that calculate IP Header Checksum using this example.
So first i have my IP header bytes:
byte[] arr = {
69, 0, 0, 60, 28, 70, 64, 0, 64, 6,
0, 0, 172, 16, 10, 99, 172, 16, 10, 12
};
Here i am add all pairs of bytes:
public static ushort[] AddPairs(byte[] arr)
{
List<ushort> pairs = new List<ushort>();
for (int i = 0; i < arr.Length; i += 2)
{
byte b1 = arr[i];
byte b2 = arr[i + 1];
ushort add = (ushort)((arr[i] << 8) + arr[i + 1]);
pairs.Add(add);
}
return pairs.ToArray();
}
And here i need to calculate the Checksum:
public static void ComputeHeaderIpChecksum(byte[] arr)
{
ushort[] pairs = AddPairs(arr);
ushort result;
ushort tmp = 0;
for (int i = 0; i < pairs.Length; i++)
{
result = (ushort)(pairs[i] + pairs[i + 1]);
tmp = result;
}
}
So first after add 2 values how can i check if this is valid ushort without the carry ?
i am kind of stuck here and don't know what to do next and will glad for some help.
C code for checksum from microchip
WORD CalcIPChecksum(BYTE *buffer, WORD count)
{
// wordval = CalcIPChecksum(&pEEPROMbuf[0x0800 + 6], 51);
WORD i;
WORD *val;
union
{
WORD w[2];
DWORD dw;
} sum;
i = count >> 1;
val = (WORD *)buffer;
//unsigned char temp;
// Calculate the sum of all words
sum.dw = 0L;
while(i--)
{
//temp = *val;
sum.dw += (DWORD)*val++;
}
// Add in the sum of the remaining byte, if present
if (count & 0x1)
{
DWORD temp = (DWORD)*(BYTE *)val;
sum.dw += temp;
}
// Do an end-around carry (one's complement arrithmetic)
sum.dw = sum.w[0] + sum.w[1];
// Do another end-around carry in case if the prior add
// caused a carry out
sum.w[0] += sum.w[1];
WORD answer = ~sum.w[0];
// Return the resulting checksum
return ;
}
Same function in c#
private UInt16 CalcIPChecksum(byte[] buffer, ushort count,int offset)
{
ushort i =0;
byte[] val = StatMethods.memcpy(ref buffer, offset, count);// get_byte_arr(buffer, count, offset);
// public static byte[] memcpy(ref byte[] ar, int startposition, int offset)
UInt32 sum_dw = 0;
i = (ushort)(count >> 1);
sum_dw = 0;
int j = 0;
while (i > 0)
{
UInt16 restored = BitConverter.ToUInt16(val, j);
sum_dw += restored;
String s = sum_dw.ToString("X");
System.Diagnostics.Debug.WriteLine("Number: "+i+" -- "+"value:" + s);
j += 2;
i--;
}
var aa = count & 0x1;
if (Convert.ToBoolean(aa))
{
byte restored = val[j];
sum_dw += (byte)restored;
}
byte[] sum_wb = BitConverter.GetBytes(sum_dw);
UInt16 sum_w0 = (UInt16)((UInt16)sum_wb[0] + (UInt32)(sum_wb[1]<<8));
UInt16 sum_w1 = (UInt16)((UInt16)sum_wb[2] + (UInt32)(sum_wb[3] << 8));
sum_dw = (UInt32)sum_w0 + (UInt32 )sum_w1;
sum_wb = BitConverter.GetBytes(sum_dw);
sum_w0 = (UInt16)((UInt16)sum_wb[0] + (UInt32)(sum_wb[1] << 8));
sum_w1 = (UInt16)((UInt16)sum_wb[2] + (UInt32)(sum_wb[3] << 8));
sum_w0 += sum_w1;
var reverse = ~(sum_w0);
UInt16 ans = (UInt16)(~(sum_w0));
System.Diagnostics.Debug.WriteLine("Asnwer: "+reverse);
return (UInt16)reverse;
}
Hope it helps

Recursive Quicksort throws stack overflow exception

I have written a recursive quicksort algorithm in c# using Visual Studio. What seems weird is ,when the input which is the collection of number that will be sorted,is lower than 9500 in array it gives the result in both best,worse,and avarage case. However, when the input is greater than 9500 it throws a stackoverflow exception. I know there were another question that is nearly same as my question in site but I did the condition also which can recursive.
public int[] quick(int [] myarray,int p,int r)
{
int q;
if (p < r)
{
q = partition(myarray, p, r);
quick(myarray, p, q - 1);
quick(myarray, q + 1, r);
}
return myarray;
}
public int partition(int [] myarray, int left, int right)
{
int i = left - 1;
int tmp = 0;
int pivot = myarray[right];
for (int j = left; j < right; j++)
{
if (myarray[j] < pivot)
{
i = i + 1;
tmp = myarray[i];
myarray[i] = myarray[j];
myarray[j] = tmp;
}
}
tmp = myarray[i + 1];
myarray[i + 1] = myarray[right];
myarray[right] = tmp;
return i + 1;
}
static void Main(string[] args)
{
Stopwatch mwatch = new Stopwatch();
Program quickprogram = new Program();
int[] mydizi = new int[9000];
//int counter = 9000;
//initialization of quick array
for (int i = 0; i < mydizi.Length; i++)
{
mydizi[i] = i + 1;
}
int[] result = new int[9000]; //return array
//time is starting
mwatch.Start();
//algorithm is called
result = quickprogram.quick(mydizi,0,mydizi.Length-1);
//result is returned from quickprogram
for (long j = 0; j < result.Length;j++)
{
Console.Write(result[j] + ",");
}
mwatch.Stop();
//time is up
//Printing the time that show how it takes
Console.Write("Ms:" + mwatch.Elapsed.Milliseconds + " S:" + mwatch.Elapsed.Seconds + " Mn:" + mwatch.Elapsed.Minutes + " Hr:" + mwatch.Elapsed.Hours);
Console.ReadLine();
}
You do a worst-case quicksort. The array is already sorted and you try to sort it again.
Next, your partition() code indeed looks strange:
int i = left - 1; // i = left-1
int pivot = myarray[right];
for (int j = left; j < right; j++) // j = left
{
if (myarray[j] < pivot)
{
i = i + 1; // now i = left-1+1 = left = j
tmp = myarray[i];
myarray[i] = myarray[j];
myarray[j] = tmp;
// congratulations!
// you successfully exchanged a value with itself!
}
In the end result, you call quick() recursively with these arguments (with array size = 9):
quick( 0, 8)
> quick( 0, 7)
>> quick( 0, 6)
>>> quick( 0, 5)
>>>> quick( 0, 4)
>>>>> quick( 0, 3)
>>>>>> quick( 0, 2)
>>>>>>> quick( 0, 1)
>>>>>>>> quick( 0, 0)
>>>>>>>> quick( 2, 1)
>>>>>>> quick( 3, 2)
>>>>>> quick( 4, 3)
>>>>> quick( 5, 4)
>>>> quick( 6, 5)
>>> quick( 7, 6)
>> quick( 8, 7)
> quick( 9, 8)
You see that doing this with 9000 elements will easily reach a recursion level of 9000 nested calls.

How do you randomly zero a bit in an integer?

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 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
so in the end, Kyteland is now the winner.
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;
}
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;
}
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;
}
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?
You can turn on any bit by OR'ing it with 1 and turn it off by AND'ing with the bitwise complement.
Here's an example that selects a random 1-bit and turns it off.
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...
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();
}
}
}
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.
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;
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;
}
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;
}
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.
bitwise XOR your number with the bit mask. If you're unfamiliar with the operator it's the hat operator: ^
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.
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.
Edit 2:
2 is correct,(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.
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.
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.
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).
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.
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.
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.
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);
}
int val=382
int mask = ~(1 << N)
// this would turn-off nth bit (0 to 31)
NewVal = (int) ((uint)val & (uint)mask}

Categories