2016-07-12 21 views
5

Cho mã sau đóng gói bốn byte giá trị vào một uint.Hoạt động toán học trên các giá trị số được đóng gói

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

Có thể áp dụng khai thác toán học như *, +,/and - trên giá trị theo cách mà nó có thể được giải nén vào đúng byte tương đương?

EDIT.

Để làm rõ, nếu tôi cố gắng để nhân giá trị bằng một giá trị đóng gói

uint result = this.PackedValue * other.PackedValue 

Sau đó giải nén bằng cách sử dụng sau đây ...

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

tôi nhận được kết quả sai.

Đây là mẫu mã đầy đủ hiển thị kết quả mong đợi và thực tế.

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

Tại sao bạn không thử? –

+1

@roryap Tôi có nhưng tôi nhận được các giá trị sai trở lại, một cái gì đó đang tràn. –

+2

Ahhh, tôi sẽ nói bạn nên bao gồm một chút trong câu hỏi của bạn. –

Trả lời

5

Lý do duy nhất nó không hoạt động cho 1.5f là do phao không đủ chính xác. Hãy thử 1.5d (đối với double) và ví dụ của bạn sẽ hoạt động. Tuy nhiên, cách tiếp cận này được giới hạn trong các trường hợp "đẹp", tức là những trường hợp kết quả trong mỗi byte được đảm bảo là một số nguyên. Trường hợp đặc biệt là khi bạn nhân với một số nguyên, sẽ luôn hoạt động miễn là không có kết quả nào trong số bốn kết quả bị tràn.

Cũng có thể thực hiện điều này để cộng và trừ miễn là không có byte nào bị tràn. Rõ ràng là bất kỳ tràn sẽ mess lên byte gần đó. Điều này đặc biệt có vấn đề nếu bạn muốn sử dụng bổ sung 2 cho các byte âm (-128 .. 127) vì việc thêm 3 đến -2 cũng là một "tràn" và sẽ làm hỏng byte tiếp theo.

+0

Cảm ơn điều đó, thông tin nhất! –

+1

Thực ra ... Hãy suy nghĩ về nó, OP muốn nhiều 4uints cùng nhau trong một bước mà không bị tràn. Tôi nghĩ rằng trong những năm 90 intel thực hiện một fuss lớn về cách có một tính năng xử lý mới cho rằng ... https://blogs.msdn.microsoft.com/dotnet/2014/11/05/using-system-numerics-vector -cho-đồ họa-lập trình/ – Aron

+0

@Aron Điểm tốt. nội bộ trong Vector sẽ có mã xử lý kịch bản này. –

0

Một giải pháp tuyệt vời hơn cho vấn đề của bạn là sử dụng 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; 
    } 

} 

Chúng tôi tạo ra một loại mới, thay vì làm chút chuyển, mang đến cho bạn trực tiếp (loại an toàn) truy cập vào các địa chỉ bộ nhớ mà là bên trong uint.

+0

Nhưng làm cách nào để nhân X, Y, Z và W lên 1,5 lần? Tôi nghĩ đó là câu hỏi của OP. –

+0

@romkyns 'uint i = 1.5f * foo.Value;' Nhưng tất nhiên sự từ chối trách nhiệm của bạn về độ chính xác và tràn sẽ áp dụng như nhau. Nó dễ đọc hơn nhiều. – Aron

+0

@Aron Blitting chắc chắn là một cách tiếp cận dễ dàng hơn và sạch hơn nhiều để quản lý cấu trúc nói chung. –

Các vấn đề liên quan