2012-11-26 27 views
6

tôi có dòng mã này:Làm thế nào để sử dụng các phép toán bit để thay thế các toán tử modulu và phân chia?

base_num = (arr[j]/base)%256; 

dòng này chạy trong một vòng lặp và các hoạt động "/" và "%" mất rất nhiều nguồn lực và thời gian để thực hiện. Tôi muốn thay đổi dòng này và áp dụng các hoạt động bit để tối đa hóa hiệu năng chương trình. Làm thế nào tôi có thể làm điều đó?

Cảm ơn.

+0

'Cơ số' có phải là hằng số hay không thay đổi? – Xymostech

+9

Nếu trình biên dịch có giá trị bất cứ điều gì, nó thay thế '% 256' bằng' & 0xFF' trên mọi nền tảng nơi nó nhanh hơn '%'. Giá trị của 'base' là gì? –

+0

Bạn có thể khai báo 'base_num' là số nguyên 8 bit (chưa ký) –

Trả lời

7

Nếu cơ số là lũy thừa thứ n của hai, bạn có thể thay thế phân chia theo số đó bằng bit thập phân của n sang phải. Sau đó, kể từ khi lấy mod 256 của một số nguyên tương đương với lấy 8 bit cuối cùng của nó, bạn có thể AND với 0xFF. Cách khác, bạn có thể đảo ngược hoạt động nếu bạn VÀ nó với 256 * base và sau đó bitshift n sang bên phải.

base_num = arr[j] >> n; 
base_num &= 0xFF; 

Tất nhiên, bất kỳ trình biên dịch nửa chiều nào cũng có thể thực hiện việc này cho bạn.

+1

Bạn cần thay đổi bằng các bit 'n',' 2^n' là '1 << n'. –

+1

Chức năng 'pow' của [http://www.kernel.org) (từ [glibc] (http://ftp.gnu.org/gnu/glibc/) được định nghĩa ở trên cùng (đơn giản hóa): 'if (base == 2) {return (1 << exp)}' –

+0

Bạn nói đúng, tôi sẽ sửa nó :) –

3

Thêm -O1 hoặc cao hơn vào tùy chọn trình biên dịch của bạn và trình biên dịch sẽ làm điều đó cho bạn.

Trong gcc, -O1 bật -ftree-slsr đó là, theo các tài liệu,

Thực hiện giảm sức mạnh đường thẳng trên cây. Điều này nhận ra các biểu thức liên quan liên quan đến phép nhân và thay thế chúng bằng các phép tính ít tốn kém hơn khi có thể.

Điều này sẽ thay thế modulo và cơ sở nếu nó không đổi. Tuy nhiên, nếu bạn biết rằng cơ số sẽ là một số điện không liên tục của hai, bạn có thể cấu trúc lại mã xung quanh để cung cấp cho bạn số log2 của số đó và >> bởi số tiền đó trừ đi một.

1

Bạn cũng có thể chỉ cần khai báo base_num là một số nguyên 8 bit:

#include <stdint.h> 

uint8_t base_num; 
uint16_t crap; 
crap = 0xFF00; 
base_num = crap; 

Nếu trình biên dịch của bạn là lời khen tiêu chuẩn, nó sẽ đặt giá trị của byte(0xFF00) (0x00) vào base_num.

Tôi chưa gặp một trình biên dịch mà không bão hòa số học ở đồng bằng C (không phải C++ hoặc C#), nhưng nếu có, nó sẽ đặt giá trị của sat_byte(0xFF00) mà là lớn hơn 0xFF, nó sẽ đưa 0xFF vào base_num.

Hãy nhớ rằng trình biên dịch của bạn sẽ cảnh báo bạn về sự mất chính xác trong trường hợp này. Trình biên dịch của bạn có thể bị lỗi trong trường hợp này (Visual Studio hiện với Treat Warnings as Errors Bật). Nếu điều đó xảy ra, bạn chỉ có thể làm:

base_num = (uint8_t)crap; 

nhưng điều này có vẻ giống như những gì bạn đang cố tránh.

Điều bạn đang cố làm dường như là xóa toán tử mô đun vì yêu cầu một phép chia và phép chia là phép toán số học cơ bản tốn kém nhất.Tôi thường sẽ không nghĩ về điều này như một nút cổ chai trong bất kỳ cách nào như bất kỳ trình biên dịch "thông minh" (ngay cả trong chế độ gỡ lỗi) sẽ "tối ưu hóa" nó để:

base_num = crap & 0xFF; 

trên một nền tảng được hỗ trợ (mỗi bộ vi xử lý chính tôi đã đã nghe về - x86, AMD64, ARM, MIPS). Tôi sẽ chết lặng khi nghe một bộ xử lý không có chỉ dẫn số học AND và OR cơ bản.