Is there any way to get the functionality of the Sql Server 2005+ Sequential Guid generator without inserting records to read it back on round trip or invoking a native win dll call? I saw someone answer with a way of using rpcrt4.dll but I'm not sure if that would be able to work from my hosted environment for production.
Edit: Working with #John Boker's answer I attempted to turn it into more of a GuidComb generator instead of being dependent on the last generated Guid other than starting over. That for the seed instead of starting with Guid.Empty that I use
public SequentialGuid()
{
var tempGuid = Guid.NewGuid();
var bytes = tempGuid.ToByteArray();
var time = DateTime.Now;
bytes[3] = (byte) time.Year;
bytes[2] = (byte) time.Month;
bytes[1] = (byte) time.Day;
bytes[0] = (byte) time.Hour;
bytes[5] = (byte) time.Minute;
bytes[4] = (byte) time.Second;
CurrentGuid = new Guid(bytes);
}
I based that off the comments on
// 3 - the least significant byte in Guid ByteArray
[for SQL Server ORDER BY clause]
// 10 - the most significant byte in Guid ByteArray
[for SQL Server ORDERY BY clause]
SqlOrderMap = new[] {3, 2, 1, 0, 5, 4, 7, 6, 9, 8, 15, 14, 13, 12, 11, 10};
Does this look like the way I'd want to seed a guid with the DateTime or does it look like I should do it in reverse and work backwards from the end of the SqlOrderMap indexes? I'm not too concerned about their being a paging break anytime an initial guid would be created since it would only occur during application recycles.
Edit: 2020+ update
At this point I strongly prefer Snowflake identifiers using something like https://github.com/RobThree/IdGen
You could just use the same Win32 API function that SQL Server uses:
UuidCreateSequential
and apply some bit-shifting to put the values into big-endian order.
And since you want it in C#:
private class NativeMethods
{
[DllImport("rpcrt4.dll", SetLastError=true)]
public static extern int UuidCreateSequential(out Guid guid);
}
public static Guid NewSequentialID()
{
//Code is released into the public domain; no attribution required
const int RPC_S_OK = 0;
Guid guid;
int result = NativeMethods.UuidCreateSequential(out guid);
if (result != RPC_S_OK)
return Guid.NewGuid();
//Endian swap the UInt32, UInt16, and UInt16 into the big-endian order (RFC specified order) that SQL Server expects
//See https://stackoverflow.com/a/47682820/12597
//Short version: UuidCreateSequential writes out three numbers in litte, rather than big, endian order
var s = guid.ToByteArray();
var t = new byte[16];
//Endian swap UInt32
t[3] = s[0];
t[2] = s[1];
t[1] = s[2];
t[0] = s[3];
//Endian swap UInt16
t[5] = s[4];
t[4] = s[5];
//Endian swap UInt16
t[7] = s[6];
t[6] = s[7];
//The rest are already in the proper order
t[8] = s[8];
t[9] = s[9];
t[10] = s[10];
t[11] = s[11];
t[12] = s[12];
t[13] = s[13];
t[14] = s[14];
t[15] = s[15];
return new Guid(t);
}
See also
Is there a .NET equalent to SQL Servers newsequentialid()
Microsoft's UuidCreateSequential is just an implementation of a type 1 uuid from RFC 4122.
A uuid has three important parts:
node: (6 bytes) - the computer's MAC address
timestamp: (7 bytes) - number of 100 ns intervals since 00:00:00.00, 15 October 1582 (the date of Gregorian reform to the Christian calendar)
clockSequenceNumber (2 bytes) - counter in case you generate a guid faster than 100ns, or you change your mac address
The basic algorithm is:
obtain a system-wide lock
read the last node, timestamp and clockSequenceNumber from persistent storage (registry/file)
get the current node (i.e. MAC address)
get the current timestamp
a) if the saved state was not available or corrupted, or the mac address has changed, generate a random clockSequenceNumber
b) if the state was available, but the current timestamp is the same or older than the saved timestamp, increment the clockSequenceNumber
save node, timestamp and clockSequenceNumber back to persistent storage
release the global lock
format the guid structure according to the rfc
There is a 4-bit version number, and 2 bit variant that also need to be ANDed into the data:
guid = new Guid(
timestamp & 0xFFFFFFFF, //timestamp low
(timestamp >> 32) & 0xFFFF, //timestamp mid
((timestamp >> 40) & 0x0FFF), | (1 << 12) //timestamp high and version (version 1)
(clockSequenceNumber & 0x3F) | (0x80), //clock sequence number and reserved
node[0], node[1], node[2], node[3], node[4], node[5], node[6]);
Note: Completely untested; i just eyeballed it from the RFC.
the byte order might have to be changed (Here is byte order for sql server)
you might want to create your own version, e.g. Version 6 (version 1-5 are defined). That way you're guaranteed to be universally unique
this person came up with something to make sequential guids, here's a link
http://developmenttips.blogspot.com/2008/03/generate-sequential-guids-for-sql.html
relevant code:
public class SequentialGuid {
Guid _CurrentGuid;
public Guid CurrentGuid {
get {
return _CurrentGuid;
}
}
public SequentialGuid() {
_CurrentGuid = Guid.NewGuid();
}
public SequentialGuid(Guid previousGuid) {
_CurrentGuid = previousGuid;
}
public static SequentialGuid operator++(SequentialGuid sequentialGuid) {
byte[] bytes = sequentialGuid._CurrentGuid.ToByteArray();
for (int mapIndex = 0; mapIndex < 16; mapIndex++) {
int bytesIndex = SqlOrderMap[mapIndex];
bytes[bytesIndex]++;
if (bytes[bytesIndex] != 0) {
break; // No need to increment more significant bytes
}
}
sequentialGuid._CurrentGuid = new Guid(bytes);
return sequentialGuid;
}
private static int[] _SqlOrderMap = null;
private static int[] SqlOrderMap {
get {
if (_SqlOrderMap == null) {
_SqlOrderMap = new int[16] {
3, 2, 1, 0, 5, 4, 7, 6, 9, 8, 15, 14, 13, 12, 11, 10
};
// 3 - the least significant byte in Guid ByteArray [for SQL Server ORDER BY clause]
// 10 - the most significant byte in Guid ByteArray [for SQL Server ORDERY BY clause]
}
return _SqlOrderMap;
}
}
}
Here is how NHibernate implements the Guid.Comb algorithm:
private Guid GenerateComb()
{
byte[] guidArray = Guid.NewGuid().ToByteArray();
DateTime baseDate = new DateTime(1900, 1, 1);
DateTime now = DateTime.UtcNow;
// Get the days and milliseconds which will be used to build the byte string
TimeSpan days = new TimeSpan(now.Ticks - baseDate.Ticks);
TimeSpan msecs = now.TimeOfDay;
// Convert to a byte array
// Note that SQL Server is accurate to 1/300th of a millisecond so we divide by 3.333333
byte[] daysArray = BitConverter.GetBytes(days.Days);
byte[] msecsArray = BitConverter.GetBytes((long) (msecs.TotalMilliseconds / 3.333333));
// Reverse the bytes to match SQL Servers ordering
Array.Reverse(daysArray);
Array.Reverse(msecsArray);
// Copy the bytes into the guid
Array.Copy(daysArray, daysArray.Length - 2, guidArray, guidArray.Length - 6, 2);
Array.Copy(msecsArray, msecsArray.Length - 4, guidArray, guidArray.Length - 4, 4);
return new Guid(guidArray);
}
Maybe interesting to compare with the other suggestions:
EntityFramework Core also implements a sequentialGuidValueGenerator.
They generate randoms guids for each value and only change the most significant bytes based on a timestamp and thread-safe increments for sorting in SQL Server.
source link
This leads to values that are all very different but with a timestamp sortable.
C# Version
public static Guid ToSeqGuid()
{
Int64 lastTicks = -1;
long ticks = System.DateTime.UtcNow.Ticks;
if (ticks <= lastTicks)
{
ticks = lastTicks + 1;
}
lastTicks = ticks;
byte[] ticksBytes = BitConverter.GetBytes(ticks);
Array.Reverse(ticksBytes);
Guid myGuid = new Guid();
byte[] guidBytes = myGuid.ToByteArray();
Array.Copy(ticksBytes, 0, guidBytes, 10, 6);
Array.Copy(ticksBytes, 6, guidBytes, 8, 2);
Guid newGuid = new Guid(guidBytes);
string filepath = #"C:\temp\TheNewGuids.txt";
using (StreamWriter writer = new StreamWriter(filepath, true))
{
writer.WriteLine("GUID Created = " + newGuid.ToString());
}
return newGuid;
}
}
}
My solution (in VB but easy to convert). It changes the most significant (for SQL Server sorting) first 8 bytes of the GUID to DateTime.UtcNow.Ticks and also has extra code to help the issue of getting the same Ticks multiple times if you call for a new GUID faster than the system clock updates.
Private ReadOnly _toSeqGuidLock As New Object()
''' <summary>
''' Replaces the most significant eight bytes of the GUID (according to SQL Server ordering) with the current UTC-timestamp.
''' </summary>
''' <remarks>Thread-Safe</remarks>
<System.Runtime.CompilerServices.Extension()> _
Public Function ToSeqGuid(ByVal guid As Guid) As Guid
Static lastTicks As Int64 = -1
Dim ticks = DateTime.UtcNow.Ticks
SyncLock _toSeqGuidLock
If ticks <= lastTicks Then
ticks = lastTicks + 1
End If
lastTicks = ticks
End SyncLock
Dim ticksBytes = BitConverter.GetBytes(ticks)
Array.Reverse(ticksBytes)
Dim guidBytes = guid.ToByteArray()
Array.Copy(ticksBytes, 0, guidBytes, 10, 6)
Array.Copy(ticksBytes, 6, guidBytes, 8, 2)
Return New Guid(guidBytes)
End Function
Not specifically guid but I now normally use a Snowflake style sequential id generator. The same benefits of a guid while having even better clustered index compatibility than a sequential guid.
Flakey for .NET Core
IdGen for .NET Framework
I just took the NHibernate based answer by Moslem Ben Dhaou and made it an extension function:
using System;
namespace Atlas.Core.Kernel.Extensions
{
public static class Guids
{
public static Guid Comb(this Guid source)
{
byte[] guidArray = source.ToByteArray();
DateTime baseDate = new DateTime(1900, 1, 1);
DateTime now = DateTime.Now;
// Get the days and milliseconds which will be used to build the byte string
TimeSpan days = new TimeSpan(now.Ticks - baseDate.Ticks);
TimeSpan msecs = now.TimeOfDay;
// Convert to a byte array
// Note that SQL Server is accurate to 1/300th of a millisecond so we divide by 3.333333
byte[] daysArray = BitConverter.GetBytes(days.Days);
byte[] msecsArray = BitConverter.GetBytes((long)(msecs.TotalMilliseconds / 3.333333));
// Reverse the bytes to match SQL Servers ordering
Array.Reverse(daysArray);
Array.Reverse(msecsArray);
// Copy the bytes into the guid
Array.Copy(daysArray, daysArray.Length - 2, guidArray, guidArray.Length - 6, 2);
Array.Copy(msecsArray, msecsArray.Length - 4, guidArray, guidArray.Length - 4, 4);
return new Guid(guidArray);
}
}
}
As far I know NHibernate have special generator, called GuidCombGenerator. You can look on it.
I ended up writing this C# class to achieve the following that I needed with SQLite (in which GUIDs are stored as BLOBs and sort order is determined by memcmp). I suppose it is not a real GUID but it's tested and it does it job on SQLite.
Sortable (memcmp) sequential 16-byte array
Using counter to guarantee correct ordering
Thread safe
The time resolution seems to vary on OSes and on my Windows it's worse than 1ms. Therefore I chose to use a second bsed resolution where the first 34 bits represent the UnixTime (UTC), and then there is a 22 bit thread safe counter which increments for every request on the same second. If the counter reaches its max, the function sleeps for 500ms and tries again.
On my laptop I could generate and store ~3,2M 16 byte arrays per second.
The class returns a 16-byte array, not a GUID.
namespace SeqGuid
{
public static class SeqGuid
{
static private Object _lock = new Object();
static Random _rnd = new Random();
static UInt64 _lastSecond = 0;
static int _counter = 0;
public static UInt64 UnixTime()
{
return (UInt64)DateTime.UtcNow.Subtract(DateTime.UnixEpoch).TotalSeconds;
}
public static byte[] CreateGuid()
{
// One year is 3600*24*365.25 = 31557600 seconds
// With 34 bits we can hold ~544 years since 1970-01-01
//
UInt64 seconds = UnixTime();
lock (_lock)
{
if (seconds == _lastSecond)
{
// 22 bits counter, aka 11-1111-1111-1111-1111-1111 / 0x3F FFFF; 4.1M max / second, 1/4 ns
_counter++;
if (_counter >= 0x3F_FFFF)
{
Thread.Sleep(500);
// http://msdn.microsoft.com/en-us/library/c5kehkcz.aspx
// A lock knows which thread locked it. If the same thread comes again it just increments a counter and does not block.
return CreateGuid();
}
}
else
{
_lastSecond = seconds;
_counter = 0;
}
}
// Create 56 bits (7 bytes) {seconds (34bit), _counter(22bit)}
UInt64 secondsctr = (seconds << 22) | (UInt64)_counter;
byte[] byte16 = new byte[16] {
(byte) ((secondsctr >> 48) & 0xFF),
(byte) ((secondsctr >> 40) & 0xFF),
(byte) ((secondsctr >> 32) & 0xFF),
(byte) ((secondsctr >> 24) & 0xFF),
(byte) ((secondsctr >> 16) & 0xFF),
(byte) ((secondsctr >> 8) & 0xFF),
(byte) ((secondsctr >> 0) & 0xFF),
(byte) _rnd.Next(0,255),
(byte) _rnd.Next(0,255), (byte) _rnd.Next(0,255),
(byte) _rnd.Next(0,255), (byte) _rnd.Next(0,255),
(byte) _rnd.Next(0,255), (byte) _rnd.Next(0,255),
(byte) _rnd.Next(0,255), (byte) _rnd.Next(0,255)};
return byte16;
}
}
}
Related
I've read the other posts on BitArray conversions and tried several myself but none seem to deliver the results I want.
My situation is as such, I have some c# code that controls an LED strip. To issue a single command to the strip I need at most 28 bits
1 bit for selecting between 2 led strips
6 for position (Max 48 addressable leds)
7 for color x3 (0-127 value for color)
Suppose I create a BitArray for that structure and as an example we populate it semi-randomly.
BitArray ba = new BitArray(28);
for(int i = 0 ;i < 28; i++)
{
if (i % 3 == 0)
ba.Set(i, true);
else
ba.Set(i, false);
}
Now I want to stick those 28 bits in 4 bytes (The last 4 bits can be a stop signal), and finally turn it into a String so I can send the string via USB to the LED strip.
All the methods I've tried convert each 1 and 0 as a literal char which is not the goal.
Is there a straightforward way to do this bit compacting in C#?
Well you could use BitArray.CopyTo:
byte[] bytes = new byte[4];
ba.CopyTo(bytes, 0);
Or:
int[] ints = new int[1];
ba.CopyTo(ints, 0);
It's not clear what you'd want the string representation to be though - you're dealing with naturally binary data rather than text data...
I wouldn't use a BitArray for this. Instead, I'd use a struct, and then pack that into an int when I need to:
struct Led
{
public readonly bool Strip;
public readonly byte Position;
public readonly byte Red;
public readonly byte Green;
public readonly byte Blue;
public Led(bool strip, byte pos, byte r, byte g, byte b)
{
// set private fields
}
public int ToInt()
{
const int StripBit = 0x01000000;
const int PositionMask = 0x3F; // 6 bits
// bits 21 through 26
const int PositionShift = 20;
const int ColorMask = 0x7F;
const int RedShift = 14;
const int GreenShift = 7;
int val = Strip ? 0 : StripBit;
val = val | ((Position & PositionMask) << PositionShift);
val = val | ((Red & ColorMask) << RedShift);
val = val | (Blue & ColorMask);
return val;
}
}
That way you can create your structures easily without having to fiddle with bit arrays:
var blue17 = new Led(true, 17, 0, 0, 127);
var blah22 = new Led(false, 22, 15, 97, 42);
and to get the values:
int blue17_value = blue17.ToInt();
You can turn the int into a byte array easily enough with BitConverter:
var blue17_bytes = BitConverter.GetBytes(blue17_value);
It's unclear to me why you want to send that as a string.
I can't think of a good way to do this, and would appreciate some help, if possible!
I'm afraid I don't have any code to post yet as I haven't got that far.
I need to generate a sequence of values from 3 (or possible more) parameters in the range 0-999.
The value must always be the same for the given inputs but with a fair distribution between upper and lower boundaries so as to appear random.
For example:
function (1, 1, 1) = 423
function (1, 1, 2) = 716
function (1, 2, 1) = 112
These must be reasonably fast to produce, by which I mean I should be able to generate 100-200 during web page load with no noticeable delay.
The method must be do-able in C# but also in JavaScript, otherwise I'd probably use a CRC32 or MD5 hash algorithm.
If it helps this will be used as part of a procedural generation routine.
I had a go at asking this previously, but I think the poor quality of my explanation let me down.
I apologise if this is worded badly. Please just let me know if so and I'll try to explain further.
Thanks very much for any help.
Here's one:
function sequence(x, y, z) {
return Math.abs(441*x-311*y+293*z) % 1000;
}
It even produces the output from your example!
Using the Marsaglia generator from the Wiki
public class SimpleMarsagliaRandom
{
private const uint original_w = 1023;
private uint m_w = original_w; /* must not be zero */
private uint m_z = 0; /* must not be zero, initialized by the constructor */
public SimpleMarsagliaRandom()
{
this.init(666);
}
public void init(uint z)
{
this.m_w = original_w;
this.m_z = z;
}
public uint get_random()
{
this.m_z = 36969 * (this.m_z & 65535) + (this.m_z >> 16);
this.m_w = 18000 * (this.m_w & 65535) + (this.m_w >> 16);
return (this.m_z << 16) + this.m_w; /* 32-bit result */
}
public uint get_random(uint min, uint max)
{
// max excluded
uint num = max - min;
return (this.get_random() % num) + min;
}
}
and
simpleMarsagliaRandom = function()
{
var original_w = 1023 >>> 0;
var m_w = 0, m_z = 0;
this.init = function(z)
{
m_w = original_w;
m_z = z >>> 0;
};
this.init(666);
var internalRandom = function()
{
m_z = (36969 * (m_z & 65535) + (m_z >>> 16)) >>> 0;
m_w = (18000 * (m_w & 65535) + (m_w >>> 16)) >>> 0;
return (((m_z << 16) >>> 0) + m_w) >>> 0; /* 32-bit result */
};
this.get_random = function(min, max)
{
if (arguments.length < 2)
{
return internalRandom();
}
var num = ((max >>> 0) - (min >>> 0)) >>> 0;
return ((internalRandom() % num) + min) >>> 0;
}
};
In Javascript all the >>> are to coerce the number to uint
Totally untested
Be aware that what is done in get_random to make numbers from x to y is wrong. Low numbers will happen a little more times than higher numbers. To make an example: let's say you have a standard 6 faces dice. You roll it, you get 1-6. Now let's say you print on it the numbers 0-5. You roll it, you get 0-5. No problems. But you need the numbers in the range 0-3. So you do roll % 3... So we have:
rolled => rolled % 3
0 => 0,
1 => 1,
2 => 2,
3 => 0,
4 => 1,
5 => 2,
6 => 0.
The 0 result is more common.
Ideone for C# version: http://ideone.com/VQudcV
JSFiddle for Javascript version: http://jsfiddle.net/dqayk/
You should be able to use MD5 hashing in both C# and JS.
In C#:
int Hash(params int[] values)
{
System.Security.Cryptography.MD5 hasher = MD5.Create();
string valuesAsString = string.Join(",", values);
var hash = hasher.ComputeHash(Encoding.UTF8.GetBytes(valuesAsString));
var hashAsInt = BitConverter.ToInt32(hash, 0);
return Math.Abs(hashAsInt % 1000);
}
In JS, implement the same method using some MD5 algorithm (e.g. jshash)
I want to convert an int to a byte[2] array using BCD.
The int in question will come from DateTime representing the Year and must be converted to two bytes.
Is there any pre-made function that does this or can you give me a simple way of doing this?
example:
int year = 2010
would output:
byte[2]{0x20, 0x10};
static byte[] Year2Bcd(int year) {
if (year < 0 || year > 9999) throw new ArgumentException();
int bcd = 0;
for (int digit = 0; digit < 4; ++digit) {
int nibble = year % 10;
bcd |= nibble << (digit * 4);
year /= 10;
}
return new byte[] { (byte)((bcd >> 8) & 0xff), (byte)(bcd & 0xff) };
}
Beware that you asked for a big-endian result, that's a bit unusual.
Use this method.
public static byte[] ToBcd(int value){
if(value<0 || value>99999999)
throw new ArgumentOutOfRangeException("value");
byte[] ret=new byte[4];
for(int i=0;i<4;i++){
ret[i]=(byte)(value%10);
value/=10;
ret[i]|=(byte)((value%10)<<4);
value/=10;
}
return ret;
}
This is essentially how it works.
If the value is less than 0 or greater than 99999999, the value won't fit in four bytes. More formally, if the value is less than 0 or is 10^(n*2) or greater, where n is the number of bytes, the value won't fit in n bytes.
For each byte:
Set that byte to the remainder of the value-divided-by-10 to the byte. (This will place the last digit in the low nibble [half-byte] of the current byte.)
Divide the value by 10.
Add 16 times the remainder of the value-divided-by-10 to the byte. (This will place the now-last digit in the high nibble of the current byte.)
Divide the value by 10.
(One optimization is to set every byte to 0 beforehand -- which is implicitly done by .NET when it allocates a new array -- and to stop iterating when the value reaches 0. This latter optimization is not done in the code above, for simplicity. Also, if available, some compilers or assemblers offer a divide/remainder routine that allows retrieving the quotient and remainder in one division step, an optimization which is not usually necessary though.)
Here's a terrible brute-force version. I'm sure there's a better way than this, but it ought to work anyway.
int digitOne = year / 1000;
int digitTwo = (year - digitOne * 1000) / 100;
int digitThree = (year - digitOne * 1000 - digitTwo * 100) / 10;
int digitFour = year - digitOne * 1000 - digitTwo * 100 - digitThree * 10;
byte[] bcdYear = new byte[] { digitOne << 4 | digitTwo, digitThree << 4 | digitFour };
The sad part about it is that fast binary to BCD conversions are built into the x86 microprocessor architecture, if you could get at them!
Here is a slightly cleaner version then Jeffrey's
static byte[] IntToBCD(int input)
{
if (input > 9999 || input < 0)
throw new ArgumentOutOfRangeException("input");
int thousands = input / 1000;
int hundreds = (input -= thousands * 1000) / 100;
int tens = (input -= hundreds * 100) / 10;
int ones = (input -= tens * 10);
byte[] bcd = new byte[] {
(byte)(thousands << 4 | hundreds),
(byte)(tens << 4 | ones)
};
return bcd;
}
maybe a simple parse function containing this loop
i=0;
while (id>0)
{
twodigits=id%100; //need 2 digits per byte
arr[i]=twodigits%10 + twodigits/10*16; //first digit on first 4 bits second digit shifted with 4 bits
id/=100;
i++;
}
More common solution
private IEnumerable<Byte> GetBytes(Decimal value)
{
Byte currentByte = 0;
Boolean odd = true;
while (value > 0)
{
if (odd)
currentByte = 0;
Decimal rest = value % 10;
value = (value-rest)/10;
currentByte |= (Byte)(odd ? (Byte)rest : (Byte)((Byte)rest << 4));
if(!odd)
yield return currentByte;
odd = !odd;
}
if(!odd)
yield return currentByte;
}
Same version as Peter O. but in VB.NET
Public Shared Function ToBcd(ByVal pValue As Integer) As Byte()
If pValue < 0 OrElse pValue > 99999999 Then Throw New ArgumentOutOfRangeException("value")
Dim ret As Byte() = New Byte(3) {} 'All bytes are init with 0's
For i As Integer = 0 To 3
ret(i) = CByte(pValue Mod 10)
pValue = Math.Floor(pValue / 10.0)
ret(i) = ret(i) Or CByte((pValue Mod 10) << 4)
pValue = Math.Floor(pValue / 10.0)
If pValue = 0 Then Exit For
Next
Return ret
End Function
The trick here is to be aware that simply using pValue /= 10 will round the value so if for instance the argument is "16", the first part of the byte will be correct, but the result of the division will be 2 (as 1.6 will be rounded up). Therefore I use the Math.Floor method.
I made a generic routine posted at IntToByteArray that you could use like:
var yearInBytes = ConvertBigIntToBcd(2010, 2);
static byte[] IntToBCD(int input) {
byte[] bcd = new byte[] {
(byte)(input>> 8),
(byte)(input& 0x00FF)
};
return bcd;
}
How can I convert an int to a bit array?
If I e.g. have an int with the value 3 I want an array, that has the length 8 and that looks like this:
0 0 0 0 0 0 1 1
Each of these numbers are in a separate slot in the array that have the size 8.
Use the BitArray class.
int value = 3;
BitArray b = new BitArray(new int[] { value });
If you want to get an array for the bits, you can use the BitArray.CopyTo method with a bool[] array.
bool[] bits = new bool[b.Count];
b.CopyTo(bits, 0);
Note that the bits will be stored from least significant to most significant, so you may wish to use Array.Reverse.
And finally, if you want get 0s and 1s for each bit instead of booleans (I'm using a byte to store each bit; less wasteful than an int):
byte[] bitValues = bits.Select(bit => (byte)(bit ? 1 : 0)).ToArray();
To convert the int 'x'
int x = 3;
One way, by manipulation on the int :
string s = Convert.ToString(x, 2); //Convert to binary in a string
int[] bits= s.PadLeft(8, '0') // Add 0's from left
.Select(c => int.Parse(c.ToString())) // convert each char to int
.ToArray(); // Convert IEnumerable from select to Array
Alternatively, by using the BitArray class-
BitArray b = new BitArray(new byte[] { x });
int[] bits = b.Cast<bool>().Select(bit => bit ? 1 : 0).ToArray();
Use Convert.ToString (value, 2)
so in your case
string binValue = Convert.ToString (3, 2);
I would achieve it in a one-liner as shown below:
using System;
using System.Collections;
namespace stackoverflowQuestions
{
class Program
{
static void Main(string[] args)
{
//get bit Array for number 20
var myBitArray = new BitArray(BitConverter.GetBytes(20));
}
}
}
Please note that every element of a BitArray is stored as bool as shown in below snapshot:
So below code works:
if (myBitArray[0] == false)
{
//this code block will execute
}
but below code doesn't compile at all:
if (myBitArray[0] == 0)
{
//some code
}
I just ran into an instance where...
int val = 2097152;
var arr = Convert.ToString(val, 2).ToArray();
var myVal = arr[21];
...did not produce the results I was looking for. In 'myVal' above, the value stored in the array in position 21 was '0'. It should have been a '1'. I'm not sure why I received an inaccurate value for this and it baffled me until I found another way in C# to convert an INT to a bit array:
int val = 2097152;
var arr = new BitArray(BitConverter.GetBytes(val));
var myVal = arr[21];
This produced the result 'true' as a boolean value for 'myVal'.
I realize this may not be the most efficient way to obtain this value, but it was very straight forward, simple, and readable.
To convert your integer input to an array of bool of any size, just use LINQ.
bool[] ToBits(int input, int numberOfBits) {
return Enumerable.Range(0, numberOfBits)
.Select(bitIndex => 1 << bitIndex)
.Select(bitMask => (input & bitMask) == bitMask)
.ToArray();
}
So to convert an integer to a bool array of up to 32 bits, simply use it like so:
bool[] bits = ToBits(65, 8); // true, false, false, false, false, false, true, false
You may wish to reverse the array depending on your needs.
Array.Reverse(bits);
int value = 3;
var array = Convert.ToString(value, 2).PadLeft(8, '0').ToArray();
public static bool[] Convert(int[] input, int length)
{
var ret = new bool[length];
var siz = sizeof(int) * 8;
var pow = 0;
var cur = 0;
for (var a = 0; a < input.Length && cur < length; ++a)
{
var inp = input[a];
pow = 1;
if (inp > 0)
{
for (var i = 0; i < siz && cur < length; ++i)
{
ret[cur++] = (inp & pow) == pow;
pow *= 2;
}
}
else
{
for (var i = 0; i < siz && cur < length; ++i)
{
ret[cur++] = (inp & pow) != pow;
pow *= 2;
}
}
}
return ret;
}
I recently discovered the C# Vector<T> class, which uses hardware acceleration (i.e. SIMD: Single-Instruction Multiple Data) to perform operations across the vector components as single instructions. In other words, it parallelizes array operations, to an extent.
Since you are trying to expand an integer bitmask to an array, perhaps you are trying to do something similar.
If you're at the point of unrolling your code, this would be an optimization to strongly consider. But also weigh this against the costs if you are only sparsely using them. And also consider the memory overhead, since Vectors really want to operate on contiguous memory (in CLR known as a Span<T>), so the kernel may be having to twiddle bits under the hood when you instantiate your own vectors from arrays.
Here is an example of how to do masking:
//given two vectors
Vector<int> data1 = new Vector<int>(new int[] { 1, 0, 1, 0, 1, 0, 1, 0 });
Vector<int> data2 = new Vector<int>(new int[] { 0, 1, 1, 0, 1, 0, 0, 1 });
//get the pairwise-matching elements
Vector<int> mask = Vector.Equals(data1, data2);
//and return values from another new vector for matches
Vector<int> whenMatched = new Vector<int>(new int[] { 1, 2, 3, 4, 5, 6, 7, 8 });
//and zero otherwise
Vector<int> whenUnmatched = Vector<int>.Zero;
//perform the filtering
Vector<int> result = Vector.ConditionalSelect(mask, whenMatched, whenUnmatched);
//note that only the first half of vector components render in the Debugger (this is a known bug)
string resultStr = string.Join("", result);
//resultStr is <0, 0, 3, 4, 5, 6, 0, 0>
Note that the VS Debugger is bugged, showing only the first half of the components of a vector.
So with an integer as your mask, you might try:
int maskInt = 0x0F;//00001111 in binary
//convert int mask to a vector (anybody know a better way??)
Vector<int> maskVector = new Vector<int>(Enumerable.Range(0, Vector<int>.Count).Select(i => (maskInt & 1<<i) > 0 ? -1 : 0).ToArray());
Note that the (signed integer) -1 is used to signal true, which has binary representation of all ones.
Positive 1 does not work, and you can cast (int)-1 to uint to get every bit of the binary enabled, if needed (but not by using Enumerable.Cast<>()).
However this only works for int32 masks up to 2^8 because of the 8-element capacity in my system (that supports 4x64-bit chunks). This depends on the execution environment based on the hardware capabilities, so always use Vector<T>.Capacity.
You therefore can get double the capacity with shorts as ints as longs (the new Half type isn't yet supported, nor is "Decimal", which are the corresponding float/double types to int16 and int128):
ushort maskInt = 0b1111010101010101;
Vector<ushort> maskVector = new Vector<ushort>(Enumerable.Range(0, Vector<ushort>.Count).Select(i => (maskInt & 1<<i) > 0 ? -1 : 0).Select(x => (ushort)x).ToArray());
//string maskString = string.Join("", maskVector);//<65535, 0, 65535, 0, 65535, 0, 65535, 0, 65535, 0, 65535, 0, 65535, 65535, 65535, 65535>
Vector<ushort> whenMatched = new Vector<ushort>(Enumerable.Range(1, Vector<ushort>.Count).Select(i => (ushort)i).ToArray());//{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
Vector<ushort> whenUnmatched = Vector<ushort>.Zero;
Vector<ushort> result = Vector.ConditionalSelect(maskVector, whenMatched, whenUnmatched);
string resultStr = string.Join("", result);//<1, 0, 3, 0, 5, 0, 7, 0, 9, 0, 11, 0, 13, 14, 15, 16>
Due to how integers work, being signed or unsigned (using the most significant bit to indicate +/- values), you might need to consider that too, for values like converting 0b1111111111111111 to a short. The compiler will usually stop you if you try to do something that appears to be stupid, at least.
short maskInt = unchecked((short)(0b1111111111111111));
Just make sure you don't confuse the most-significant bit of an int32 as being 2^31.
Using & (AND)
Bitwise Operators
The answers above are all correct and effective. If you wanted to do it old-school, without using BitArray or String.Convert(), you would use bitwise operators.
The bitwise AND operator & takes two operands and returns a value where every bit is either 1, if both operands have a 1 in that place, or a 0 in every other case. It's just like the logical AND (&&), but it takes integral operands instead of boolean operands.
Ex. 0101 & 1001 = 0001
Using this principle, any integer AND the maximum value of that integer is itself.
byte b = 0b_0100_1011; // In base 10, 75.
Console.WriteLine(b & byte.MaxValue); // byte.MaxValue = 255
Result: 75
Bitwise AND in a loop
We can use this to our advantage to only take specific bits from an integer by using a loop that goes through every bit in a positive 32-bit integer (i.e., uint) and puts the result of the AND operation into an array of strings which will all be "1" or "0".
A number that has a 1 at only one specific digit n is equal to 2 to the nth power (I typically use the Math.Pow() method).
public static string[] GetBits(uint x) {
string[] bits = new string[32];
for (int i = 0; i < 32; i++) {
uint bit = x & Math.Pow(2, i);
if (bit == 1)
bits[i] = "1";
else
bits[i] = "0";
}
return bits;
}
If you were to input, say, 1000 (which is equivalent to binary 1111101000), you would get an array of 32 strings that would spell 0000 0000 0000 0000 0000 0011 1110 1000 (the spaces are just for readability).
I need to pass a parameter as two int parameters to a Telerik Report since it cannot accept Long parameters. What is the easiest way to split a long into two ints and reconstruct it without losing data?
Using masking and shifting is your best bet. long is guaranteed to be 64 bit and int 32 bit, according to the documentation, so you can mask off the bits into the two integers and then recombine.
See:
static int[] long2doubleInt(long a) {
int a1 = (int)(a & uint.MaxValue);
int a2 = (int)(a >> 32);
return new int[] { a1, a2 };
}
static long doubleInt2long(int a1, int a2)
{
long b = a2;
b = b << 32;
b = b | (uint)a1;
return b;
}
static void Main(string[] args)
{
long a = 12345678910111213;
int[] al = long2doubleInt(a);
long ap = doubleInt2long(al[0],al[1]);
System.Console.WriteLine(ap);
System.Console.ReadKey();
}
Note the use of bitwise operations throughout. This avoids the problems one might get when using addition or other numerical operations that might occur using negative numbers or rounding errors.
Note you can replace int with uint in the above code if you are able to use unsigned integers (this is always preferable in this sort of situation, as it's a lot clearer what's going on with the bits).
Doing bit-manipulation in C# can be awkward at times, particularly when dealing with signed values. You need to be using unsigned values whenever you plan on doing bit-manipulation. Unfortunately it's not going to yield the nicest looking code.
const long LOW_MASK = ((1L << 32) - 1);
long value = unchecked((long)0xDEADBEEFFEEDDEAD);
int valueHigh = (int)(value >> 32);
int valueLow = (int)(value & LOW_MASK);
long reconstructed = unchecked((long)(((ulong)valueHigh << 32) | (uint)valueLow));
If you want a nicer way to do this, get the raw bytes for the long and get the corresponding integers from the bytes. The conversion to/from representations doesn't change very much.
long value = unchecked((long)0xDEADBEEFFEEDDEAD);
byte[] valueBytes = BitConverter.GetBytes(value);
int valueHigh = BitConverter.ToInt32(valueBytes, BitConverter.IsLittleEndian ? 4 : 0);
int valueLow = BitConverter.ToInt32(valueBytes, BitConverter.IsLittleEndian ? 0 : 4);
byte[] reconstructedBytes = BitConverter.IsLittleEndian
? BitConverter.GetBytes(valueLow).Concat(BitConverter.GetBytes(valueHigh)).ToArray()
: BitConverter.GetBytes(valueHigh).Concat(BitConverter.GetBytes(valueLow)).ToArray();
long reconstructed = BitConverter.ToInt64(reconstructedBytes, 0);
For unigned the following will work:
ulong value = ulong.MaxValue - 12;
uint low = (uint)(value & (ulong)uint.MaxValue);
uint high = (uint)(value >> 32);
ulong value2 = ((ulong)high << 32) | low;
long x = long.MaxValue;
int lo = (int)(x & 0xffffffff);
int hi = (int)((x - ((long)lo & 0xffffffff)) >> 32);
long y = ((long)hi << 32) | ((long)lo & 0xffffffff);
Console.WriteLine(System.Convert.ToString(x, 16));
Console.WriteLine(System.Convert.ToString(lo, 16));
Console.WriteLine(System.Convert.ToString(hi, 16));
Console.WriteLine(System.Convert.ToString(y, 16));
Converting it to and from a string would be much simpler than converting it two and from a pair of ints. Is this an option?
string myStringValue = myLongValue.ToString();
myLongValue = long.Parse(myStringValue);
Instead of mucking with bit operations, just use a faux union. This also would work for different combinations of data types, not just long & 2 ints. More importantly, that avoids the need to be concerned about signs, endianness or other low-level details when you really only care about reading & writing bits in a consistent manner.
using System;
using System.Runtime.InteropServices;
public class Program
{
[StructLayout(LayoutKind.Explicit)]
private struct Mapper
{
[FieldOffset(0)]
public long Aggregated;
[FieldOffset(0)]
public int One;
[FieldOffset(sizeof(int))]
public int Two;
}
public static void Main()
{
var layout = new Mapper{ Aggregated = 0x00000000200000001 };
var one = layout.One;
var two = layout.Two;
Console.WriteLine("One: {0}, Two: {1}", one, two);
var secondLayout = new Mapper { One = one, Two = two };
var aggregated = secondLayout.Aggregated;
Console.WriteLine("Aggregated: {0}", aggregated.ToString("X"));
}
}