2009-10-23 9 views
10

Có là đã nhận được một cách nhanh hơn và tốt hơn để trao đổi byte từ 16bit sau đó này .:cách nhanh hơn để trao đổi endianness trong C# với 16 lời chút

public static void Swap(byte[] data) 
{ 
    for (int i = 0; i < data.Length; i += 2) 
    { 
     byte b = data[i]; 
     data[i] = data[i + 1]; 
     data[i + 1] = b; 
    } 
} 

Có ai có một ý tưởng?

+2

Giải pháp của bạn có vẻ giống như một giải pháp tốt, ngoại trừ NẾU DỮ LIỆU CỦA BẠN ĐƯỢC BAO GIỜ ĐƯỢC NGAY LẬP TỨC, mã của bạn sẽ ném mảng ra khỏi ngoại lệ bị ràng buộc. – NawaMan

+1

Nếu anh ấy đổi 16 bit, thì dữ liệu của anh ấy sẽ không bao giờ có độ dài kỳ lạ. –

+0

Có, đây sẽ là một phương pháp riêng tư và nó sẽ được đảm bảo có các từ 16 bit. – initialZero

Trả lời

7

Trong nỗ lực của tôi để đăng ký giải thưởng Uberhacker, tôi gửi những điều sau đây. Để thử nghiệm của tôi, tôi đã sử dụng một mảng Nguồn 8.192 byte và gọi SwapX2 100.000 lần:

public static unsafe void SwapX2(Byte[] source) 
{ 
    fixed (Byte* pSource = &source[0]) 
    { 
     Byte* bp = pSource; 
     Byte* bp_stop = bp + source.Length; 

     while (bp < bp_stop) 
     { 
      *(UInt16*)bp = (UInt16)(*bp << 8 | *(bp + 1)); 
      bp += 2; 
     } 
    } 
} 

điểm chuẩn của tôi chỉ ra rằng phiên bản này là nhanh hơn so với mã trình trong câu hỏi ban đầu hơn 1,8 lần.

1

Vâng, bạn có thể sử dụng XOR swapping trick để tránh byte trung gian. Nó sẽ không nhanh hơn, và tôi sẽ không ngạc nhiên nếu IL giống hệt nhau.

for (int i = 0; i < data.Length; i += 2) 
{ 
    data[i] ^= data[i + 1]; 
    data[i + 1] ^= data[i]; 
    data[i] ^= data[i + 1]; 
} 
+1

Tốt nhất. Nhưng điều này hơi khó hiểu hơn. Và wikipedia tuyên bố "Trên CPU hiện đại (máy tính để bàn), kỹ thuật XOR là chậm hơn đáng kể so với sử dụng một biến tạm thời để làm trao đổi." Oh well. Cảm ơn vì giải pháp gợi cảm. – initialZero

+0

Vâng, tôi nghĩ tất cả những gì chúng tôi có thể nói về nó là nó gọn gàng. Tôi chỉ đánh giá nó, và có kết quả giống hệt với giải pháp của bạn. Vì vậy, một trong các hình thức có khả năng được tối ưu hóa cho các hình thức khác. –

6

Bằng cách này dường như là hơi nhanh hơn so với phương pháp này trong câu hỏi ban đầu:

private static byte[] _temp = new byte[0]; 
public static void Swap(byte[] data) 
{ 
    if (data.Length > _temp.Length) 
    { 
     _temp = new byte[data.Length]; 
    } 
    Buffer.BlockCopy(data, 1, _temp, 0, data.Length - 1); 
    for (int i = 0; i < data.Length; i += 2) 
    { 
     _temp[i + 1] = data[i]; 
    } 
    Buffer.BlockCopy(_temp, 0, data, 0, data.Length); 
} 

điểm chuẩn của tôi cho rằng phương pháp này được gọi là liên tục, do đó thay đổi kích thước của mảng _temp không phải là một yếu tố. Phương pháp này dựa trên thực tế là một nửa số trao đổi byte có thể được thực hiện với lệnh gọi Buffer.BlockCopy(...) ban đầu (với vị trí nguồn được bù đắp bằng 1).

Hãy chuẩn bị điểm này cho chính mình, trong trường hợp tôi đã hoàn toàn mất trí. Trong các thử nghiệm của tôi, phương pháp này mất khoảng 70% miễn là phương pháp ban đầu (mà tôi đã sửa đổi để khai báo byte b bên ngoài vòng lặp).

+0

Giải thưởng Uberhacker! Tôi sẽ mong đợi một sự thay đổi kích thước lớn của temp để được đắt hơn một trao đổi tại chỗ. Và nó là một bộ nhớ bị rò rỉ chỉ có nhiệt độ ngồi xung quanh. – initialZero

+1

@initialZero: trong tiêu chuẩn của tôi, ban đầu tôi có kích thước nó với cùng kích thước như mảng thử nghiệm của tôi, vì vậy không có chi phí ở đó. Nhiệt độ biến như thế này nói chung là mua tốc độ với chi phí của bộ nhớ, mà có thể hoặc có thể không phải là một quyết định tốt. – MusiGenesis

+0

@MusiGenesis bạn luôn có thể đặt temp = null ở cuối hoán đổi để sửa lỗi. Đó chắc chắn là một giải pháp tuyệt vời. Cảm ơn. – initialZero

4

Tôi luôn luôn thích điều này:

public static Int64 SwapByteOrder(Int64 value) 
{ 
    var uvalue = (UInt64)value; 
    UInt64 swapped = 
     ((0x00000000000000FF) & (uvalue >> 56) 
     | (0x000000000000FF00) & (uvalue >> 40) 
     | (0x0000000000FF0000) & (uvalue >> 24) 
     | (0x00000000FF000000) & (uvalue >> 8) 
     | (0x000000FF00000000) & (uvalue << 8) 
     | (0x0000FF0000000000) & (uvalue << 24) 
     | (0x00FF000000000000) & (uvalue << 40) 
     | (0xFF00000000000000) & (uvalue << 56)); 
    return (Int64)swapped; 
} 

Tôi tin rằng bạn sẽ tìm thấy điều này là phương pháp nhanh nhất cũng một là khá dễ đọc và an toàn. Rõ ràng điều này áp dụng cho các giá trị 64 bit nhưng kỹ thuật tương tự có thể được sử dụng cho 32- hoặc 16-.