Reputation: 1524
I am struggling to unpack my data from a long type to two numbers. Not sure where i am going wrong.
I create a unique number from two numbers by packing them into a long:
public static long Squeeze(float x, float y)
{
return ((long)x << 32) | (long)y;
}
So the long consists for 4 bytes for x then 4 bytes for y.
Then i am trying to get the numbers back out with:
float x = (float)(hash >> 32);
float y = (float)(hash | int.MaxValue); // this should be 1111 1111 1111 1111 i think
But it doesn't seem to work, x
appears to be correct, but y
is giving me numbers that it should not.
Also it needs to work for negative numbers too.
Example:
(2.0, 9.0) => Packed: 8589934601 => Unpacked: (2, 1.073742E+10)
(-1.0, -1.0) => Packed: -1 => Unpacked: (-1.0, -2147484000.0)
Upvotes: 2
Views: 303
Reputation: 1505
Here's an Endian agnostic version of Patrick Roberts' answer.
public static long PackLong(int x, int y)
{
var bytes = new byte[8];
if (BitConverter.IsLittleEndian)
{
BitConverter.GetBytes(x).CopyTo(bytes, 4);
BitConverter.GetBytes(y).CopyTo(bytes, 0);
}
else
{
BitConverter.GetBytes(x).CopyTo(bytes, 0);
BitConverter.GetBytes(y).CopyTo(bytes, 4);
}
return BitConverter.ToInt64(bytes, 0);
}
public static void UnpackLong(long value, out int x, out int y)
{
var bytes = BitConverter.GetBytes(value);
if (BitConverter.IsLittleEndian)
{
x = BitConverter.ToInt32(bytes, 4);
y = BitConverter.ToInt32(bytes, 0);
}
else
{
x = BitConverter.ToInt32(bytes, 0);
y = BitConverter.ToInt32(bytes, 4);
}
}
A helper function like this can be quite misleading when Endianess is not accounted for.
Upvotes: 0
Reputation: 51886
You should use BitConverter
instead of casting:
public static long Squeeze(float x, float y)
{
var bytes = new byte[8];
BitConverter.GetBytes(x).CopyTo(bytes, 0);
BitConverter.GetBytes(y).CopyTo(bytes, 4);
return BitConverter.ToInt64(bytes, 0);
}
and
public static void Unpack(long value, out float x, out float y)
{
var bytes = BitConverter.GetBytes(value);
x = BitConverter.ToSingle(bytes, 0);
y = BitConverter.ToSingle(bytes, 4);
}
As long as you're not transferring the byte array out of the program, it doesn't matter whether the system uses little endian or big endian byte ordering. If you need to know, you can check BitConverter.IsLittleEndian
.
Upvotes: 4
Reputation: 8962
You need &
(bitwise and) instead of |
(bitwise or) to extract by mask:
unchecked
{
...
float y = (float)(int)(hash & (long)uint.MaxValue)
}
Upvotes: 4