2013-03-21 33 views
14

Một mẫu rất phổ biến trong lập trình là giới hạn giá trị tối đa sau một số loại cập nhật. Những gì tôi muốn biết là nếu có sự khác biệt giữa hai miếng mã sau đây, và nếu một nên được ưa thích:Trong C++, tốt hơn là giới hạn giá trị sử dụng std :: min hoặc một nhánh?

value += increment; 
value = std::min(value, valueMax); 

vs

value += increment; 

if (value > valueMax) 
    value = valueMax; 

suy nghĩ của tôi là điều này đi xuống cho dù CPU có hướng dẫn lấy hai giá trị và sản xuất minumum. Nếu vậy, lệnh gọi lệnh std :: min sẽ dẫn đến lệnh này và tránh một nhánh không cần thiết. Nếu không, phiên bản thứ hai sẽ tránh được việc gán không cần thiết khi giá trị < = valueMax.

Tôi không phải là người rất tốt với loại điều này, nhưng tôi chắc chắn rằng có những tin tặc lắp ráp trường học cũ, những người sẽ biết điều này. Đối với họ tôi hỏi: cái nào tốt hơn?

+2

Hãy thử cả hai và xem hội đồng ... – Mysticial

+0

Tôi muốn nói phiên bản đầu tiên sẽ luôn hoạt động * ít nhất * cũng như phiên bản thứ hai, vì vậy không có lý do gì để không sử dụng nó. Phiên bản đầu tiên có thể * cũng * nhanh hơn, mặc dù không có gì đảm bảo về điều đó. –

+0

Giống như bí mật ngụ ý, nó phụ thuộc vào việc thực hiện std :: min (http://en.cppreference.com/w/cpp/algorithm/min). – DavidA

Trả lời

10

Trình biên dịch hiện đại đủ thông minh để tạo cùng mã trong cả hai trường hợp. Ví dụ, 32-bit GCC tạo:

addl %esi, %edi 
cmpl %edx, %edi 
movl %edi, %eax 
cmovgl %edx, %eax 

64-bit Clang:

%1 = add nsw i32 %increment, %value 
%2 = icmp sgt i32 %1, %valueMax 
%value = select i1 %2, i32 %valueMax, i32 %1 
+0

+1. Bạn có thể đưa ra một số chú thích cho hội đồng ở đây không? Có chi nhánh nào không? – voltrevo

+2

@ Mozza314 Không có chi nhánh nào ở đây. Trình biên dịch đã làm tốt như có thể được thực hiện - đó là sử dụng một động thái có điều kiện. – Mysticial

4

On VC10 Phát hành cho đoạn mã sau chúng ta có lắp ráp sau:

int main(int argc, char *argv[]) 
{ 
    int dummyValue = 0, valueMax = 3000, value = valueMax + 1; 

    cin >> valueMax; 
    cin >> value; 

    dummyValue = std::min(value, valueMax); 

    cout << dummyValue; 
    cin >> valueMax; 
    cin >> value; 

    if (value > valueMax) 
    dummyValue = valueMax; 

    cout << dummyValue; 
    return 0; 
} 

tạo :

24: dummyValue = std::min(value, valueMax); 
00E112AF mov   eax,dword ptr [valueMax] 
00E112B2 cmp   eax,dword ptr [value] 
00E112B5 lea   edx,[value] 
00E112B8 lea   ecx,[valueMax] 
00E112BB cmovge  ecx,edx  // <-- this is our conditional assignment 
00E112BE mov   esi,dword ptr [ecx] 

if (value > valueMax) 
    dummyValue = valueMax 
00E112ED mov   eax,dword ptr [valueMax] 
00E112F0 cmp   dword ptr [value],eax 
00E112F3 mov   ecx,dword ptr ds:[0E13038h] 
00E112F9 cmovg  esi,eax 

Vì vậy, cả hai trường hợp được tối ưu hóa theo hướng dẫn cmovge hoặc cmovg.

Tôi vẫn sẽ đi với std::min vì nó cho thấy ý định tốt hơn tuyên bố if. Nó được tối ưu hóa và nó dễ đọc hơn.

+0

Khi bạn cung cấp các giá trị không đổi cho các biến cho các thuật toán đơn giản như min (được inline hầu hết thời gian). Trình biên dịch có thể tìm ra, tại thời gian biên dịch, giá trị tối thiểu. Vòng lặp sẽ không được thực hiện để bạn nhận được '0'. Hãy thử tạo ra các giá trị được chuyển đến phút tại thời gian chạy và bạn sẽ nhận được phép đo thích hợp. –

+0

Trong mọi trường hợp, thử nghiệm của bạn bị hỏng theo nhiều cách. 1) Nó thực sự không làm gì cả. Vì vậy, trình biên dịch được tự do tối ưu hóa cả hai vòng lặp đó. Điều đó có thể được cố định bằng cách sử dụng kết quả của các vòng lặp. 2) Toàn bộ vòng lặp đầu tiên sẽ được tối ưu hóa thành 'dummyValue = 3001'. Và toàn bộ vòng lặp thứ hai sẽ được tối ưu hóa thành 'value = 3001'. – Mysticial

0

Câu trả lời tùy thuộc vào loại giá trị. Mã có thể được tối ưu hóa hiệu quả nếu tất cả các hoạt động hoàn toàn minh bạch với trình tối ưu hóa mã, điều này sẽ là trường hợp nếu giá trị là một số nguyên đơn giản. Nhưng mã của bạn cũng sẽ biên dịch nếu giá trị là một chuỗi std :: và sau đó phiên bản thứ hai có thể có khả năng nhanh hơn vì việc gán có điều kiện.

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