Mathematical operations on packed numerical values

Given the following code, package the four byte values ​​in uint .

 private static void Pack(byte x, byte y, byte z, byte w) { this.PackedValue = (uint)x | ((uint)y << 8) | ((uint)z << 16) | ((uint)w << 24); } 

Is it possible to apply mathematical operators like *, +, / and - to a value so that it can be unpacked into the correct byte equivalent?

EDIT.

To clarify, if I try to multiply the value by another packed value

 uint result = this.PackedValue * other.PackedValue 

Then unzip using the following ...

 public byte[] ToBytes() { return new[] { (byte)(this.PackedValue & 0xFF), (byte)((this.PackedValue >> 8) & 0xFF), (byte)((this.PackedValue >> 16) & 0xFF), (byte)((this.PackedValue >> 24) & 0xFF) }; } 

I get the wrong results.

Here is a complete code example showing the expected and actual result.

 void Main() { uint x = PackUint(128, 128, 128, 128); uint y = (uint)(x * 1.5f); byte[] b1 = ToBytes(x); x.Dump(); // 2155905152 b1.Dump(); // 128, 255, 128, 255 RIGHT! byte[] b2 = ToBytes(y); b2.Dump(); // 0, 192, 192, 192 WRONG! Should be 192, 192, 192, 192 } // Define other methods and classes here private static uint PackUint(byte x, byte y, byte z, byte w) { return ((uint)x) | ((uint)y << 8) | ((uint)z << 16) | ((uint)w << 24); } public static byte[] ToBytes(uint packed) { return new[] { (byte)(packed & 0xFF), (byte)((packed >> 8) & 0xFF), (byte)((packed >> 16) & 0xFF), (byte)((packed >> 24) & 0xFF) }; } 
+5
source share
2 answers

The only reason this does not work for 1.5f is because the floats are not accurate enough. Try 1.5d (for double ) and your example will work. However, this approach is limited to β€œgood” cases, i.e. Those where the result in each byte is guaranteed to be an integer. A special case is multiplication by an integer, which will always work until none of the four results is overflowed.

It is also possible to do for addition and subtraction, provided that none of the individual byte overflows. Obviously, any overflow will interfere with neighboring bytes. This is especially problematic if you want to use 2 padding for negative bytes (-128 .. 127), because adding 3 to -2 is also an "overflow" and will corrupt the next byte.

+5
source

A nicer solution to your problem is to use Blitting.

 void Main() { Byte X = 0x13; Byte Y = 0x6A; Byte Z = 0xA3; Byte W = 0x94; Foo foo = new Foo(X, Y, Z, W); uint i = foo ; Foo bar = (uint)(i * 1.5d); Console.WriteLine(X * 1.5d == bar.X); Console.WriteLine(Y * 1.5d == bar.Y); Console.WriteLine(Z * 1.5d == bar.Z); Console.WriteLine(W * 1.5d == bar.W); } [StructLayout(LayoutKind.Explicit)] public struct Foo { [FieldOffset(0)] public byte X; [FieldOffset(1)] public byte Y; [FieldOffset(2)] public byte Z; [FieldOffset(3)] public byte W; [FieldOffset(0)] public uint Value; public Foo(byte x, byte y, byte z, byte w) : this() { X = x; Y = y; Z = z; W = w; } public static implicit operator Foo(uint value) { return new Foo(){ Value = value }; } public static implicit operator uint(Foo foo) { return foo.Value; } } 

We are creating a new type, which instead of shifting bits gives you direct (type of safe) access to the memory address that is inside uint .

0
source

All Articles