压缩数值的数学运算

Mathematical operations on packed numerical values

给定以下代码将四个 byte 值打包成 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);
}

是否可以对值应用像 *, +, / and - 这样的数学运算符,以便将其解压缩为正确的 byte 等价物?

编辑。

澄清一下,如果我尝试将该值乘以另一个打包值

uint result  = this.PackedValue * other.PackedValue 

然后使用以下命令解压...

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

我得到了错误的结果。

这是显示预期结果和实际结果的完整代码示例。

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)
    };
}

它对 1.5f 不起作用的唯一原因是浮点数不够精确。尝试 1.5d(对于 double),您的示例将起作用。然而,这种方法仅限于 "nice" 情况,即每个字节中的结果保证为整数的情况。一种特殊情况是当您乘以一个整数时,只要四个结果中的 none 溢出,它就会始终有效。

如果 none 的单个字节溢出,也可以对加法和减法执行此操作。显然任何溢出都会弄乱附近的字节。如果您希望对负字节 (-128 .. 127) 使用 2 的补码,这尤其有问题,因为将 3 加到 -2 也是一个 "overflow" 并且会弄乱下一个字节。

使用 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;
    }

}

我们创建了一种新类型,它可以让您直接(类型安全)访问 uint.

中的内存地址,而不是进行位移。