2015-01-05 14 views
5

Nếu tôi có một vòng lặp mà tôi biết cần phải được thực hiện n lần là có một cách để viết một vòng lặp (hoặc cho) mà không có một so sánh mỗi lần? Nếu không có cách nào để thực hiện một lượt vĩ mô:Vòng lặp mà không so sánh n lần trong C

int i = 0; 
for(i = 0; i < 5; i++) { 
    operation(); 
} 

thành:

operation(); 
operation(); 
operation(); 
operation(); 
operation(); 

T.B. Đây là vòng lặp nhanh nhất mà tôi đã đưa ra cho đến nay.

int i = 5; 
while(i-- >= 0) { 
    operation(); 
} 
+4

Đó không phải là điều bạn nên làm. Trình biên dịch của bạn đã hủy bỏ vòng lặp nếu nó hiệu quả hơn. – ThiefMaster

+0

Tại sao bạn muốn làm điều đó? Nó sẽ chiếm nhiều không gian hơn trong bộ nhớ cache lệnh, yêu cầu giải mã lệnh nhiều hơn và về cơ bản sẽ tồi tệ hơn. Nếu nó tốt hơn, trình biên dịch có chuyển đổi nó cho bạn không? (Trừ khi nó là một mảnh rác, trong trường hợp này tại sao bạn sử dụng nó?) –

Trả lời

7

Trình biên dịch thông minh đầy đủ sẽ làm điều này cho bạn. Cụ thể hơn, tối ưu hóa các trình biên dịch hiểu vòng lặp unrolling. Đó là một tối ưu hóa khá cơ bản, đặc biệt là trong các trường hợp như ví dụ của bạn, nơi số lần lặp lại được biết đến lúc biên dịch.

Vì vậy, trong ngắn hạn: bật tối ưu hóa trình biên dịch và đừng lo lắng về điều đó.

0

cả hai vòng sẽ thực hiện so sánh ..

dù sao trình biên dịch phải xác định lặp liên tục và bỏ vòng lặp.

Bạn có thể kiểm tra với gcc và cờ tối ưu hóa (-O) và xem mã được tạo sau đó.

Quan trọng hơn: Không tối ưu hóa trừ khi có lý do quan trọng để làm!

5

Số lượng hướng dẫn bạn viết trong mã nguồn không liên quan chặt chẽ đến số lượng lệnh máy mà trình biên dịch sẽ tạo ra.

Hầu hết các trình biên dịch thông minh hơn và trong ví dụ thứ hai của bạn có thể tạo mã như:

operation(); 
operation(); 
operation(); 
operation(); 
operation(); 

tự động vì họ phát hiện rằng vòng lặp sẽ luôn lặp 5 lần.

Ngoài ra nếu bạn làm một tối ưu hóa hồ sơ theo định hướng và một trình biên dịch thấy rằng một vòng lặp có tí hon một cơ thể và lặp lại rất cao đếm nó có thể cuộn nó ngay cả đối với một số chung của sự lặp lại với các mã như:

while (count >= 5) { 
    operation(); 
    operation(); 
    operation(); 
    operation(); 
    operation(); 
    count -= 5; 
} 
while (count > 0) { 
    operation(); 
    count--; 
} 

Điều này sẽ làm cho số lượng lớn count s khoảng một phần năm số lần kiểm tra so với phiên bản ngây thơ.

Nếu điều này đáng làm hoặc không phải là điều gì đó mà chỉ có hồ sơ mới có thể cho biết.

Một điều bạn có thể làm gì nếu bạn biết chắc chắn rằng mã cần phải được thực hiện ít nhất một lần là viết

do { 
    operation(); 
} while (--count); 

thay vì

while (count--) { 
    operation(); 
} 

Khả năng count==0 là hơi khó chịu cho CPU vì yêu cầu trong mã do hầu hết các trình biên dịch tạo ra thêm một JMP về phía trước:

jmp test 
loop: 
    ...operation... 
test: 
    ...do the test... 
    jne loop 
.210

mã máy cho phiên bản do { ... } while thay vì chỉ đơn giản là

loop: 
    ... opertion ... 
    ... do the test... 
    jne loop 
+0

Bạn có thể bỏ vòng lặp cuối cùng với: 'switch (count) {case 4: operation(); trường hợp 3: hoạt động(); trường hợp 2: hoạt động(); trường hợp 1: thao tác(); } ' – Marian

0

Khi mã C được biên dịch, trong khi và cho vòng được chuyển đổi sang báo cáo so sánh trong ngôn ngữ máy, vì vậy không có cách nào để tránh một số loại so sánh với các vòng lặp for/while. Bạn có thể thực hiện một loạt các câu lệnh goto và số học tránh sử dụng so sánh, nhưng kết quả có lẽ sẽ kém hiệu quả hơn. Bạn nên xem xét cách các vòng lặp này được biên dịch sang ngôn ngữ máy bằng cách sử dụng radare2 hoặc gdb để xem chúng có thể được cải thiện như thế nào ở đó.

0

Với mẫu, bạn có thể cuộn vòng lặp (trong số được biết đến tại thời gian biên dịch) với một cái gì đó như:

namespace detail 
{ 

    template <std::size_t ... Is> 
    void do_operation(std::index_sequence<Is...>) 
    { 
     std::initializer_list<std::size_t>{(static_cast<void>(operation()), Is)...}; 
    } 

} 

template <std::size_t N> 
void do_operation() 
{ 
    detail::do_operation(std::make_index_sequence<N>()); 
} 

Live demo

nhưng trình biên dịch có thể đã làm được một tối ưu hóa cho bình thường vòng lặp.

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