打包数值的数学运算

时间:2016-07-12 13:10:23

标签: c# bit-shift

鉴于以下代码将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 等效值的方式?

EDIT。

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

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

我得到了错误的结果。

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

ISNUMERIC

2 个答案:

答案 0 :(得分:5)

它不适用于1.5f的唯一原因是因为浮点数不够精确。试试1.5d(对于double),您的示例将有效。然而,这种方法仅限于&#34; nice&#34;情况,即保证每个字节的结果是整数的情况。一个特例是当你乘以一个整数时,只要四个结果都没有溢出,它就会一直有效。

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

答案 1 :(得分:0)

更好的解决方案是使用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内的内存地址。