2011-10-10 66 views
6

Tôi được thông báo rằng (i >> 3) is faster than (i/8) nhưng tôi không thể tìm thấy bất kỳ thông tin nào về số >>. Bất cứ ai có thể chỉ cho tôi một liên kết giải thích nó?>> và 0xfffffff8 có nghĩa là gì?

Cùng một người nói với tôi "int k = i/8, tiếp theo là k*8 được thực hiện tốt hơn bằng cách (i&0xfffffff8);" nhưng một lần nữa Google đã không giúp m ...

Thanks cho bất kỳ liên kết!

+7

'i >> 3' là/chỉ có thể nhanh hơn' i/8' trên trình biên dịch * hoàn toàn khủng khiếp * khi tối ưu hóa. Đừng lo lắng về nó - viết mã rõ ràng hơn ;-) –

+2

Bất cứ ai nói với bạn rằng có lẽ vẫn còn sống trong * ngày vinh quang * của văn bản lắp ráp. Chuyển đổi những thứ như 'i/8' sang' i >> 3' được gọi là [giảm cường độ] (https://secure.wikimedia.org/wikipedia/en/wiki/Strength_reduction) và là một trong những tối ưu hóa cơ bản nhất được thực hiện bởi trình biên dịch. – Praetorian

Trả lời

9

Như được giải thích here toán tử >> chỉ đơn giản là thay đổi bit của các bit của i.Vì vậy, chuyển i 1 bit sang kết quả bên phải trong một số nguyên chia cho 2 và dịch chuyển 3 bit kết quả trong một phân chia bằng 2^3 = 8.

Nhưng hiện nay việc tối ưu hóa phân chia theo sức mạnh của hai không nên thực sự được thực hiện nữa, vì trình biên dịch phải đủ thông minh để tự làm điều này.

Tương tự như vậy một phép toán AND với 0xFFFFFFF8 (1 ... 1000, 3 bit cuối cùng 0) là tương đương với làm tròn xuống i đến bội số gần nhất của 8 (như (i/8)*8 không), vì nó sẽ zero 3 bit cuối cùng của i .

+0

Vui lòng cung cấp một liên kết cho OP: "Có ai có thể chỉ cho tôi một liên kết giải thích nó không?' –

+0

@JonathanM Xong, lý do tốt cho một downvote. Tôi luôn luôn giải thích các câu trả lời giải thích nhiều hơn các liên kết tới google hoặc Wikipedia, nhưng có thể bạn đang ở ngay trong đó, anh ấy đã yêu cầu một liên kết rõ ràng. –

+0

Cảm ơn tất cả vì câu trả lời! – Joel

1

Về nửa đầu:

>> là một sự thay đổi chút khôn ngoan bên phải.

Vì vậy, dịch chuyển giá trị số 3 bit sang phải cũng giống như chia cho 8 và int nhập kết quả.

Dưới đây là một tài liệu tham khảo tốt cho các nhà khai thác và ưu tiên của họ: http://web.cs.mun.ca/~michael/c/op.html

Phần thứ hai của câu hỏi của bạn liên quan đến việc điều hành &, đó là một chút khôn ngoan AND. Ví dụ là ANDing i và một số để lại tất cả các bit được đặt trừ 3 bit ít quan trọng nhất. Đó là cơ bản cùng một điều xảy ra khi bạn có một số, chia cho 8, lưu trữ kết quả dưới dạng số nguyên, sau đó nhân kết quả đó với 8.

Lý do này chia cho 8 và lưu trữ dưới dạng số nguyên cũng giống như dịch chuyển bit tới đúng 3 vị trí, và nhân với 8 và lưu trữ kết quả trong một int là giống như dịch chuyển bit sang 3 vị trí bên trái. Vì vậy, nếu bạn đang nhân hoặc chia cho một sức mạnh của 2, chẳng hạn như 8, và bạn sẽ chấp nhận cắt ngắn các bit xảy ra khi bạn lưu trữ kết quả đó trong một int, dịch chuyển bit nhanh hơn , hoạt động. Điều này là do bộ vi xử lý có thể bỏ qua thuật toán nhân/chia và chỉ cần chuyển thẳng sang các bit dịch chuyển, bao gồm vài bước.

2

Dịch chuyển bit phải. i >> 3 di chuyển i số nguyên 3 vị trí sang bên phải [cách nhị phân] - aka, chia cho 2^3.

0

>>right shift operation.

Nếu bạn có số 8, được biểu diễn dưới dạng nhị phân là 00001000, các bit dịch chuyển sang phải bằng 3 vị trí sẽ cho bạn 00000001, số thập phân 1. Điều này tương đương với chia cho 2 ba lần.

Chia và nhân với cùng một số có nghĩa là bạn đặt một số bit ở bên phải bằng 0. Điều tương tự cũng có thể được thực hiện nếu bạn áp dụng mặt nạ. Nói, 0xF8 là 11111000 bitwise và nếu bạn VÀ nó đến một số, nó sẽ thiết lập ba bit cuối cùng của nó bằng không, và các bit khác sẽ được để lại như chúng. Ví dụ: 10 & 0xF8 sẽ là 00001010 & 11111000, bằng 00001000 hoặc 8 thập phân. Tất nhiên nếu bạn sử dụng biến 32 bit, bạn nên có mặt nạ phù hợp với kích thước này, vì vậy nó sẽ có tất cả các bit được đặt thành 1, ngoại trừ ba bit ở bên phải, cho bạn số của bạn - 0xFFffFFf8.

1

Nhà điều hành >> là các nhà điều hành chút thay đổi. Phải mất bit đại diện bởi giá trị và thay đổi chúng trên một số lượng các khe được đặt ở bên phải.

0

của bạn thay đổi các bit trong hệ nhị phân để ví dụ:

1000 == 8

0100 == 4 (>> 1)

0010 == 2 (>> 2)

0001 == 1 (>> 3)

Vì bạn đang sử dụng hệ thống hai cơ sở, bạn có thể tận dụng lợi thế với các ước số nhất định (chỉ số nguyên!) Và chỉ dịch bit. Ngày đầu đó, tôi tin rằng hầu hết các trình biên dịch biết điều này và sẽ làm điều này cho bạn.

Đối với phần thứ hai:

(i & 0xfffffff8);

Giả sử i = 16

0x00000010 & 0xfffffff8 == 16

(16/8) * 8 == 16

Một lần nữa lợi dụng khai thác hợp lý trên hệ nhị phân. Điều tra cách các toán tử logic hoạt động trên nhị phân một chút để hiểu rõ hơn về những gì đang diễn ra ở mức bit (và cách đọc hex).

0

Đó gọi là chút chuyển, nó là một hoạt động trên bit, ví dụ, nếu bạn có một số trên cơ sở nhị phân, giả sử 8, nó sẽ được 1000, vì vậy

x = 1000; 
y = x >> 1; //y = 100 = 4 
z = x >> 3; //z = 1 
2

int x = i/8 * 8:

1) i/8, có thể được thay thế bằng i >> 3 - chuyển bitwise sang bên phải vào 3 chữ số (8 = 2^3)

2) i & xfffffff8 so với mặt nạ Ví dụ: bạn có:

i = 11111111 
k (i/8) would be: 00011111 
x (k * 8) would be: 11111000 

Do đó hoạt động chỉ reset 3 bit cuối cùng: Và so sánh thời gian chi phí nhân và phép chia có thể được viết lại đơn giản với

i & xfffffff8 - so sánh với (...Mặt nạ 11111000)

1

Dịch chuyển bitwise.

Giả sử tôi có một 8 -bit số nguyên, trong hệ nhị phân

Nếu tôi rời ca (>> điều hành) 1 kết quả là

Nếu sau đó tôi dịch phải (< < điều hành) 1, tôi rõ ràng có được trở lại để mặc tôi bắt đầu

Nó chỉ ra rằng vì số nguyên nhị phân đầu tiên là equivelant để

0 * 2^7 + 1 * 2^6 + 0 * 2^5 + 0 * 2^4 + 0 * 2^3 + 1 * 2^2 + 0 * 2^1 + 0 * 2^0

hoặc đơn giản 2^6 hoặc 64

Khi chúng ta phải thay đổi 1 chúng tôi nhận được sau

0 * 2^7 + 0 * 2^6 + 1 * 2^5 + 0 * 2^4 + 0 * 2^3 + 1 * 2^2 + 0 * 2^1 + 0 * 2^0

hoặc đơn giản là 2^5 hoặc 32

có nghĩa

i >> 1 

cũng giống như

i/2 

Nếu chúng ta chuyển một lần nữa (i >> 2), chúng tôi một cách hiệu quả chia 2 lần nữa và nhận được

i/2/2 

Mà thực sự là

i/4 

Không hẳn một chứng minh toán học, nhưng bạn có thể nhìn thấy những điều sau đây giữ đúng

i >> n == i/(2^n) 
0

>> dịch số sang bên phải. Hãy xem xét một số nhị phân 0001000 đại diện cho 8 trong ký hiệu thập phân. Dịch chuyển nó 3 bit sang bên phải sẽ cung cấp cho 0000001 là số 1 trong ký hiệu thập phân. Vì vậy, bạn thấy rằng mỗi 1 bit chuyển sang bên phải là trong thực tế, một bộ phận của 2. Lưu ý ở đây rằng các nhà điều hành cắt ngắn phần nổi của kết quả. Do đó i >> n ngụ ý i/2^n. Điều này có thể nhanh chóng tùy thuộc vào việc thực hiện trình biên dịch. Nhưng nó thường diễn ra ngay trong thanh ghi và do đó rất nhanh so với phân chia truyền thống và nhân lên.

Câu trả lời cho phần thứ hai được chứa trong phần thứ nhất. Kể từ khi phân chia cũng cắt ngắn tất cả các phần nổi của kết quả, sự phân chia bởi 8 sẽ trong lý thuyết thay đổi số của bạn 3 bit bên phải, do đó mất tất cả các thông tin về 3 bit bên phải. Bây giờ khi bạn nhân nó lại bằng 8 (mà theo lý thuyết có nghĩa là dịch chuyển sang trái bằng 3 bit), bạn đang đệm các bit cực đại 3 bằng không sau khi dịch chuyển kết quả còn lại 3 bit. Do đó, hoạt động hoàn chỉnh có thể được coi là một hoạt động "&" với 0xfffffff8 có nghĩa là số đó có tất cả các bit 1 trừ số tận cùng bên phải 4 bit là 1000.

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