I am currently developing a C# 2D sandbox based game. The game world is filled with tiles/blocks. Since the world is so large the game can sometimes use more than what is allowed for 32-bit application.
My tiles consist of the following data inside a struct:
public byte type;
public byte typeWall;
public byte liquid;
public byte typeLiquid;
public byte frameX;
public byte frameY;
public byte frameWallX;
public byte frameWallY;
I am looking to encapsulate all this data within one "long" (64-bit integer).
I want properties to get and set each piece of data using bit shifting, etc... (I have never done this).
Would this save space? Would it increase processing speed? If so how can it be accomplished?
Thanks.
I am looking to encapsulate all this data within one "long" (64-bit integer).
You can use StructLayoutAttribute with LayoutKind.Explicit and then decorate fields with FieldOffsetAttribute specifying the exact position.
I want properties to get and set each piece of data using bit shifting, etc... (I have never done this).
Then use shift left (<<), shift right (>>) and masking (and && to extract / or || to write (don't forget about any non-zero bits in the target byte)) with 0xff to separate individual bytes. Read more about bitwise operations here.
Would this save space? Would it increase processing speed?
Did you measure it? Did you discover a performace / memory consuption problem? If yes, go optimize it. If not, do not do premature optimizations. In other words, don't blindly try without measuring first.
I don't know why you want to do this, but you can do it in this way:
byte type = 4;
byte typeWall = 45;
byte liquid = 45;
byte typeLiquid = 234;
byte frameX = 23;
byte frameY = 23;
byte frameWallX = 22;
byte frameWallY = 221;
byte[] bytes = new [] {type, typeWall, liquid, typeLiquid, frameX, frameY, frameWallX, frameWallY};
BitConverter.ToInt64(bytes, 0);
or using << (shift) operator.
As you can see by pasting the following code into linqpad :
void Main()
{
sizeof(byte).Dump("byte size");
sizeof(Int32).Dump("int 32");
sizeof(Int64).Dump("int 64");
sizeof(char).Dump("for good measure, a char:");
}
You'll get:
byte size 1
int 32 4
int 64 8
for good measure, a char: 2
So packing 8 bytes in an int64 will be the same, but you'll have to play with the bits yourself (if that's your thing, by all means, go for it :)
Related
I am working on a serial port comms project. There is a piece of hardware sending signed 16 bit integer values, which are being received in to a C# PC application.
Each value is sent over two bytes, least significant byte first.
The performance of the is critical, so I'm looking at ways of reducing processing.
The C# Serial Port object provides a method ReadExisting, which returns the current buffered values as a string.
It also provides a method Read which can accept a byte array which is then populated with the bytes in the port buffer.
If I read all the values in to a byte array, I then have to join the two bytes together to get the 16 bit number.
I'm intrigued by the string returned from the ReadExisting method.
If I create an array of short (short[] MyValues), I could then get the memory location of the array, and simply write the string to that location. As long as I ensure the bytes are sent in the correct order, I could then simple read the 16 bit values when needed.
Alternatively, I could possibly create two arrays, one an array of shorts, the second an array of bytes twice the size of the first, both with the same memory location.
However, "here be dragons". I have no experience with C# and this level of memory access.
Some brief googleing suggests this is possible - this article has some interesting information:
https://www.developerfusion.com/article/84519/mastering-structs-in-c/
Before I head off down this particular rabbit hole, does anyone have any suggestions on how to achieve this level of memory manipulation?
Thanks
Try an overlay
static void Main(string[] args)
{
const int NUMBER_OF_BYTES = 100;
ByteInt16 byteInt = new ByteInt16();
byteInt.data = new byte[NUMBER_OF_BYTES];
byteInt.data2 = new UInt16[NUMBER_OF_BYTES / 2];
byteInt.data = Enumerable.Range(0, NUMBER_OF_BYTES).Select(x => (byte)x).ToArray();
UInt16[] results = byteInt.data2.Select(x => (UInt16)x).ToArray();
}
[StructLayout(LayoutKind.Explicit)]
public struct ByteInt16
{
[FieldOffset(0)]
public byte[] data;
[FieldOffset(0)]
public UInt16[] data2;
}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
Does C# have a 4 bit data type? I want to make a program with variables that waste the minimum amount of memory, because the program will consume a lot.
For example: I need to save a value that i know it will go from 0 to 10 and a 4 bit var can go from 0 to 15 and it's perfect. But the closest i found was the 8 bit (1 Byte) data type Byte.
I have the idea of creating a c++ dll with a custom data type. Something like nibble. But, if that's the solution to my problem, i don't know where to start, and what i have to do.
Limitations: Creating a Byte and splitting it in two is NOT an option.
No, there is no such thing as a four-bit data type in c#.
Incidentally, four bits will only store a number from 0 to 15, so it doesn't sound like it is fit for purpose if you are storing values from 0 to 127. To compute the range of a variable given that it has N bits, use the formula (2^N)-1 to calculate the maximum. 2^4 = 16 - 1 = 15.
If you need to use a data type that is less than 8 bits in order to save space, you will need to use a packed binary format and special code to access it.
You could for example store two four-bit values in a byte using an AND mask plus a bit shift, e.g.
byte source = 0xAD;
var hiNybble = (source & 0xF0) >> 4; //Left hand nybble = A
var loNyblle = (source & 0x0F); //Right hand nybble = D
Or using integer division and modulus, which works well too but maybe isn't quite as readable:
var hiNybble = source / 16;
var loNybble = source % 16;
And of course you can use an extension method.
static byte GetLowNybble(this byte input)
{
return input % 16;
}
static byte GetHighNybble(this byte input)
{
return input / 16;
}
var hiNybble = source.GetHighNybble();
var loNybble = source.GetLowNybble();
Storing it is easier:
var source = hiNybble * 16 + lowNybble;
Updating just one nybble is harder:
var source = source & 0xF0 + loNybble; //Update only low four bits
var source = source & 0x0F + (hiNybble << 4); //Update only high bits
A 4-bit data type (AKA Nib) only goes from 0-15. It requires 7 bits to go from 0-127. You need a byte essentially.
No, C# does not have a 4-bit numeric data type. If you wish to pack 2 4-bit values in a single 8-bit byte, you will need to write the packing and unpacking code yourself.
No, even boolean is 8 bits size.
You can use >> and << operators to store and read two 4 bit values from one byte.
https://msdn.microsoft.com/en-us/library/a1sway8w.aspx
https://msdn.microsoft.com/en-us/library/xt18et0d.aspx
Depending on how many of your nibbles you need to handle and how much of an issue performance is over memory usage, you might want to have a look at the BitArray and BitVector32 classes. For passing around of values, you'd still need bigger types though.
Yet another option could also be StructLayout fiddling, ... beware of dragons though.
I have a register which reads out the version number in the following format. It is little endian. For example:
The register value read is 0x15000000 but I need to represent this in the GUI as 00.00.00_15.
How do I print in particular format with taking care of reversal as well in C#?
You could use the BitConverter.GetBytes to get an array of bytes..
int num = 0x15000000;
var bytes = BitConverter.GetBytes(num);
// If you want your code to run even on your Big Endian fridge,
// decomment this line :)
// if (!BitConverter.IsLittleEndian) Array.Reverse(bytes);
string str = string.Format("{0:x2}.{1:x2}.{2:x2}_{3:x2}", bytes[0], bytes[1], bytes[2], bytes[3]);
and then string.Format("{num:x2}" where x2 will give an hex format of 2 digits
Note that in general, the BitConverter.GetBytes should be used only on Intel/AMD computers! If you want to make a generic code that can run anywhere, including your fridge, then it's better to use the next solution! (because your fridge could be Big Endian!)
Clearly you could do bit manipulation, shift >> and &
string str = string.Format("{0:x2}.{1:x2}.{2:x2}_{3:x2}", num & 0xFF, (num >> 8) & 0xFF, (num >> 16) & 0xFF, (num >> 24) & 0xFF);
But it's quite unreadable, unless you know a little of bit-manipulation :)
Don't treat it as a number - it's not a number. The fact that you can efficiently store it as a single int is irrelevant - just an implementation detail.
Once you start thinking in bytes in an array, you find that "little-endian" is not really anything important. Instead, you just have a structure that starts with one byte meaning one thing, the next one something else...
There's many ways to get to that behaviour, depending on where you get the actual value - taking an int will not give you control over endianness, for example. If you just take a byte[], you can do something like this:
string.Format("{0}.{1}.{2}_{3}", data[3], data[2], data[1], data[0])
This is usually very easy to handle when you're working with e.g. loading data from a file, or sending it over a socket. If you're dealing with native code interop, you can use a structure instead of int (or similar):
struct MyVersionNumber
{
byte Lowest;
byte Other;
byte YetAnother;
byte Highest;
}
Think in types - don't use primitives unless what you have is a primitive value. You're obviously working with a composite value that's (for whatever reason) folded into a primitive type. That's not a good idea for maintaining complexity :)
Once you have type, you can ensure proper type safety, validation, and just override the ToString method, for example, to output the value for the user.
Most but not all .net platforms are little endian. Therefore the correct usage of BitConverter.GetBytes is to not assume it will return one or the other.
int num = 0x15000000;
var bytes = BitConverter.GetBytes(num);
if (!BitConverter.IsLittleEndian) Array.Reverse(bytes); //it's big-endian, so reverse the bytes
string str = string.Format("{0:x2}.{1:x2}.{2:x2}_{3:x2}", bytes[0], bytes[1], bytes[2], bytes[3]);
I have a struct with some properties (like int A1, int A2,...). I store a list of struct as binary in a file.
Now, I'm reading the bytes from file using binary reader into Buffer and I want to apply a filter based on the struct's properties (like .A1 = 100 & .A2 = 12).
The performance is very important in my scenario, so I convert the filter criteria to byte array (Filter) and then I want to mask Buffer with Filter. If the result of masking is equal to Filter, the Buffer will be converted to the struct.
The question: What is the fastest way to mask and compare two byte arrays?
Update: The Buffer size is more than 256 bytes. I'm wondering if there is a better way rather than iterating in each byte of Buffer and Filter.
The way I would usually approach this is with unsafe code. You can use the fixed keyword to get a byte[] as a long*, which you can then iterate in 1/8th of the iterations - but using the same bit operations. You will typically have a few bytes left over (from it not being an exact multiple of 8 bytes) - just clean those up manually afterwards.
Try a simple loop with System.BitConverter.ToInt64(). Something Like this:
byte[] arr1;
byte[] arr2;
for (i = 0; i < arr1.Length; i += 8)
{
var P1 = System.BitConverter.ToInt64(arr1, i);
var P2 = System.BitConverter.ToInt64(arr2, i);
if((P1 & P2) != P1) //or whatever
//break the loop if you need to.
}
My assumption is that comparing/masking two Int64s will be much faster (especially on 64-bit machines) than masking one byte at a time.
Once you've got the two arrays - one from reading the file and one from the filter, all you then need is a fast comparison for the arrays. Check out the following postings which are using unsafe or PInvoke methods.
What is the fastest way to compare two byte arrays?
Comparing two byte arrays in .NET
I have an integer array of length 900 that contains only binary data [0,1].
I want to short the length of the array without losing binary data formate(original array values).
Is it possible to short the length of array of 900 into 10 or 20 length in C#???
Bitarray class will give you almost 1/32th of your int array's length.
You could actually apply some compression on bits and then store it. if its only 1s and 0s, Run-length encoding may help reduce size drastically in not-worst scenarios.
Run length encoding - Wiki article
Try to use System.Collections.BitArray
Here is the sample code:
using System;
using System.Collections.Generic;
using System.Text;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
System.Collections.BitArray bits = new System.Collections.BitArray(900);
// Setting all bits to 0
bits.SetAll(false);
// Here Im setting 21st bit in array
bits[21] = true;
// etc...
int[] nativeBits = new int[29];
// Packing your bits in int array
bits.CopyTo(nativeBits, 0);
// This prints 2097152. this is 2^21
Console.WriteLine("First element is:"+nativeBits[0].ToString());
}
}
}
nativeBits array consists of only 29 elements. And now you can convert it in string
In fact, you have a binary integer with 900 digits. There are lots of ways you can hold that "number" depending on the what do you want with it and how fast.
Ask yourself:
do I need fast set function ( arr[n] = something )
do I need fast retrieval function ( val = arr[n] )
do I need iteration of some kind, for example find next n for which arr[n] is 1
and so on.
Then, ask again or modify you original question.
Otherwise, BitArray
EDIT:
Since we found something (a little) I would suggest rolling your own class for that.
Class would have a container such as byte[] and methods to set and unset a item on some position.
Checking common 1s from two arrays would be as simple as &&-ing an array on byte to byte basis.