2012-01-26 32 views
6

Có thuật toán hiệu quả (nhanh) nào sẽ thực hiện mở rộng/sao chép bit không?Thuật toán để mở rộng/sao chép bit?

Ví dụ, mở rộng mỗi bit trong một giá trị 8 bit bằng 3 (tạo ra một giá trị 24bit):

1101 0101 => 11111100 01110001 11000111 

Phương pháp brute force mà đã được đề xuất là để tạo ra một bảng tra cứu. Trong tương lai, giá trị mở rộng có thể cần phải thay đổi. Tức là, trong ví dụ trên chúng ta đang mở rộng 3 nhưng có thể cần phải mở rộng bằng một số giá trị khác. Điều này sẽ yêu cầu nhiều bảng tra cứu mà tôi muốn tránh nếu có thể.

+6

Nếu bạn chỉ xử lý các giá trị 8 bit, bảng tra cứu gần như chắc chắn sẽ là lựa chọn tốt nhất. Nó sử dụng rất ít không gian. Bạn có thể cung cấp thêm thông tin chi tiết về trường hợp sử dụng của bạn và các hoạt động bạn mong đợi sẽ phổ biến không? – templatetypedef

+0

Đầu vào là luồng bit nối tiếp không đổi. Trong yêu cầu hiện tại, mỗi đoạn dữ liệu đến 8 byte tại một thời điểm, sau đó cần mỗi bit được mở rộng thêm 3 để được gửi đi dưới dạng luồng bit khác. 64bits trong 192bits ra. Một yêu cầu trong tương lai có thể liên quan đến việc thêm các bit "header" trước mỗi giá trị bit 8 mở rộng và tất nhiên là padding vào một ranh giới byte. LUTs được nhanh chóng nhưng cho bao lâu này cần phải chạy, bất kỳ cải thiện hiệu suất tiềm năng sẽ được đánh giá cao. – jivany

+1

Nhiều kiến ​​trúc có hướng dẫn giúp tăng tốc độ tính toán này. Nếu bạn không sợ phá vỡ tính tương thích đa nền tảng, hãy tận dụng những hướng dẫn này gần như chắc chắn là một chiến thắng - và nếu bạn tối ưu hóa điều gì đó về thuật toán "tầm thường" thì chuyển sang tối ưu hóa ở mức thấp là chìa khóa. – Kaganar

Trả lời

6

Có một cơ hội để làm cho nó nhanh hơn so với bảng tra cứu nếu tính toán số học là vì lý do nào đó nhanh hơn truy cập bộ nhớ. Điều này có thể xảy ra nếu các phép tính được vector hóa (PPC AltiVec hoặc Intel SSE) và/hoặc nếu các phần khác của chương trình cần sử dụng từng bit bộ nhớ cache.

Nếu hệ số mở rộng = 3, chỉ có 7 hướng dẫn là cần thiết:

out = (((in * 0x101 & 0x0F00F) * 0x11 & 0x0C30C3) * 5 & 0x249249) * 7; 

Hoặc thay thế khác, với 10 hướng dẫn:

out = (in | in << 8) & 0x0F00F; 
out = (out | out << 4) & 0x0C30C3; 
out = (out | out << 2) & 0x249249; 
out *= 7; 

Đối với yếu tố mở rộng khác> = 3:

unsigned mask = 0x0FF; 
unsigned out = in; 
for (scale = 4; scale != 0; scale /= 2) 
{ 
    shift = scale * (N - 1); 
    mask &= ~(mask << scale); 
    mask |= mask << (scale * N); 
    out = out * ((1 << shift) + 1) & mask; 
} 
out *= (1 << N) - 1; 

Hoặc giải pháp thay thế khác, cho các yếu tố mở rộng> = 2:

unsigned mask = 0x0FF; 
unsigned out = in; 
for (scale = 4; scale != 0; scale /= 2) 
{ 
    shift = scale * (N - 1); 
    mask &= ~(mask << scale); 
    mask |= mask << (scale * N); 
    out = (out | out << shift) & mask; 
} 
out *= (1 << N) - 1; 

shiftmask giá trị tốt hơn để được tính toán trước khi xử lý luồng bit.

+0

Phản hồi tuyệt vời.Đồng nghiệp của tôi và tôi đã đến gần với điều này trong khi làm một số handwaving và whiteboard brainstorming nhưng điều này là hiệu quả hơn nhiều so với cách tiếp cận của chúng tôi. Tôi sẽ phải chạy một số thử nghiệm khi chúng tôi có phần còn lại của mã được triển khai và xem giá vé như thế nào. – jivany

+0

Có ai có liên kết đến toán học đằng sau điều này không? Tôi đã tìm kiếm xung quanh nhưng chỉ tìm được phép thuật mà không giải thích về cách thức hoạt động của nó. Tôi thấy có một số hình mẫu cho các con số ma thuật nhưng mọi thứ khác đều thoát khỏi tôi. –

+0

nvm, tôi đã tìm ra. Giúp viết ra số nhị phân và sau đó tìm mẫu. Tuy nhiên, bất kỳ liên kết nào về chủ đề sẽ được đánh giá cao. https://gist.github.com/corytodd/056ed01228f59fee9a13d00fc25b9a62 –

1

Bạn có thể thực hiện một bit đầu vào tại thời điểm. Tất nhiên, nó sẽ chậm hơn một bảng tra cứu, nhưng nếu bạn đang làm một cái gì đó giống như viết cho một vi điều khiển nhỏ 8 bit mà không có đủ chỗ cho một bảng, nó sẽ có dấu chân ROM nhỏ nhất có thể.

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