2008-10-23 27 views
12

Tôi nhớ từ ngày C mà chúng ta được khuyến khích sử dụngSử dụng "lớn hơn hoặc bằng" hay chỉ là "lớn hơn"

i > -1 

thay vì

i >= 0 

vì hiệu suất.

Điều này vẫn áp dụng trong thế giới C# .NET? Hiệu quả của việc sử dụng cái này với cái khác với các trình biên dịch ngày nay là gì? tức là trình biên dịch có đủ thông minh để tối ưu hóa những thứ này cho bạn không?

(Là một sang một bên cố gắng và gõ câu hỏi "sử dụng> = hoặc>" vào trường câu hỏi về Stack Overflow và xem những gì sẽ xảy ra.)

Trả lời

44

Không, không có vấn đề về hiệu suất nào được kết hợp với toán tử so sánh. Và bất kỳ trình biên dịch tốt sẽ tối ưu hóa một cái gì đó tầm thường này anyway.

Tôi không chắc chắn nơi bạn có đề xuất sử dụng "i> -1" thay vì "i> = 0". Trên kiến ​​trúc x86, nó làm cho không có sự khác biệt mà bạn sử dụng: cả hai trường hợp mất đúng hai hướng dẫn ... một để so sánh và một để nhảy:

;; if (i > -1) { 
cmp eax, -1 
jle else 
then: 
... 
else: 

;; if (i >= 0) { 
cmp eax, 0 
jl else 
then: 
... 
else: 

Trên hầu hết các kiến ​​trúc RISC mà tôi biết, "i> = 0 "thực sự có thể nhanh hơn vì thường có một thanh ghi số không chuyên dụng, và" i> -1 "có thể yêu cầu tải một hằng số. Ví dụ, MIPS chỉ có một hướng dẫn < (không có < =). (! Ngây thơ) Sau đây là cách hai cấu trúc sẽ được thể hiện trong MIPS ngôn ngữ lắp ráp:

// if (i >= 0) { (assuming i is in register %t0) 

stl $t1, $0, $t0  // in C: t1 = (0 < t0) 
beq $t1, $0, else // jump if t1 == 0, that is if t0 >= 0 
nop 
then: 
... 
else: 

// if (i > -1) { (assuming i is in register %t0) 

addi $t2, $0, -1  // in C: t2 = -1 
stl $t1, $t2, $t0  // in C: t1 = (t2 < t0) = (-1 < t0) 
bne $t1, $0, else  // jump if t1 != 0, that is if t0 > -1 
nop 
then: 
... 
else: 

Vì vậy, trong trường hợp ngây thơ, nói chung, nó sẽ thực sự là một hướng dẫn nhanh hơn để làm "i> = 0" trên MIPS . Tất nhiên, mã RISC được tối ưu hóa rất nhiều đến nỗi một trình biên dịch có thể sẽ thay đổi một trong hai chuỗi lệnh này gần như không nhận ra :-)

Vì vậy ... câu trả lời ngắn là không không, không có sự khác biệt.

+5

'(không có không, không có sự khác biệt) =! (! (! (! Sự khác biệt))) =! (! Khác biệt)) = khác biệt';) –

+1

@ M.kazemAkhgary, khó tranh luận với. Bây giờ tôi là loại cám dỗ để thêm một thứ 5 "không" :-P –

5

Không bạn không cần phải làm điều này nữa. Có các trình biên dịch đã trở nên thông minh hơn nhiều và hai biểu thức không có sự khác biệt về hiệu suất.

+0

Tôi vẫn không thể tin rằng có bao giờ là một môi trường mà nó * sẽ * tạo sự khác biệt. Bất cứ ai có thể cho tôi biết về một kiến ​​trúc còn tồn tại, nơi một trong những yêu cầu chu kỳ ít hơn so với khác ??? –

+1

Âm thanh như một huyền thoại đô thị lập trình –

3

Tôi nhớ từ những ngày C mà chúng tôi được khuyến khích sử dụng .... vì hiệu suất.

Bạn có chắc chắn về điều đó? Tôi đã làm việc với các máy tính quay trở lại đầu những năm 70 (có, ở đầu gối của cha tôi ...), và tôi chưa bao giờ thấy một CPU không thể xử lý> = nhanh như>. (BH "Branch High" so với BNL "Branch Not Low" trong IBM360 talk).

+0

Tôi đồng ý, James. Người mà tôi có thể nghĩ là MIPS, chỉ có ít hơn. Vì vậy, trình biên dịch thường sắp xếp lại "a <= b" thành "not (b

+0

Tôi nghĩ đó là một huyền thoại phổ biến. Tôi đã nghe nó từ các đồng nghiệp và nhìn thấy nó trên internet một vài lần ngay cả trong vài năm qua. Ngay cả khi không có trình biên dịch tối ưu hóa sự khác biệt, đó là một sự lãng phí rất lớn của nỗ lực để tiết kiệm một hướng dẫn CPU. – Mnebuerquo

+0

Như bạn nói - đó có lẽ là điều mà tôi đã bị hiểu sai - cảm ơn. – Guy

9

Có một câu hỏi rất giống nhau (không chỉ trích ngụ ý - như bạn nói, tìm kiếm cho các ký hiệu là khó khăn) ở đây: "Should one use < or <= in a for loop"

(Vâng, tôi xảy ra để có thể tìm thấy nó dễ dàng như tôi đã có một rất nhiều upvotes trên câu trả lời của tôi ...)

Về cơ bản, hãy làm mọi thứ dễ đọc nhất.Ngày ai đó đoán chính xác rằng việc thực hiện thay đổi từ hình thức dễ đọc nhất sẽ giải quyết vấn đề hiệu suất (không có sự trợ giúp của một hồ sơ) là ngày tôi ngừng nói về hiệu suất :)

12

Khá ngoài thực tế là bất kỳ trình biên dịch nào cũng đúng, và ngoài thực tế là trong các kiến ​​trúc hiện đại, không có sự khác biệt về tốc độ giữa các so sánh >>=, bức tranh lớn hơn nói rằng đây là một "tối ưu hóa vi mô" không ảnh hưởng đến hiệu suất thời gian chạy trong phần lớn các trường hợp.

Trong trường hợp so sánh nó thường không ảnh hưởng đến khả năng đọc bất cứ cách nào bạn viết nó, nhưng có dịp khi chọn một ranh giới trong khác là rõ ràng hơn: ví dụ,

if (length >= str.size()) 

so

if (length > str.size() - 1) 

Tôi không biết về bạn, nhưng tôi sẽ chọn tùy chọn 1 bất kỳ ngày nào. :-) Trong trường hợp không đáng kể ảnh hưởng đến hiệu suất, chẳng hạn như điều này, tùy chọn dễ đọc hơn sẽ giành chiến thắng.

+1

Bật. "Tối ưu hóa sớm là gốc rễ của mọi điều ác". (Donald Knuth) –

+0

Lưu ý rằng nếu str.size() trả về một số không dấu, hai câu lệnh trên không tương đương. Cụ thể, câu lệnh sau sẽ không bao giờ đánh giá đúng nếu str.size() bằng không.Đôi khi tôi đã sử dụng mã như vậy, mặc dù tôi thường thêm một typecast rõ ràng để unsigned: nếu kích thước là 'short', "if (length> (unsigned short) (str.size-1))" sẽ giúp làm rõ rằng mã sẽ mong đợi hành vi gói. – supercat

2

Điều đó có thể đúng đối với một số ngôn ngữ kịch bản mờ rã mà chia nhỏ> = thành 2 so sánh, nhưng bất kỳ ai khuyến khích bạn sử dụng ngôn ngữ đó cho C ... ừm ... bạn nên cố gắng quên hết mọi thứ đã nói với bạn.

2

Điều này nhắc tôi về đề xuất sử dụng ++ i thay vì i + + (tiền gia tăng so với tăng sau) vì đó là được cho là một hướng dẫn nhanh hơn. (Tôi quên nơi ban đầu tôi đọc về điều này, nhưng nó có thể là Tạp chí Người dùng C/C++ hoặc Tạp chí Tiến sĩ Dobb nhưng tôi dường như không thể tìm thấy một tài liệu tham khảo web.)

Tôi nghiêm túc nghi ngờ rằng> hoặc> = nhanh hơn hoặc chậm hơn; thay vào đó hãy viết mã của bạn để làm rõ.

Là một lưu ý phụ, tôi đã phát triển tùy chọn cho toán tử tăng trước (++ i) ngay cả khi lý do hiện tại có thể đã lỗi thời.

+1

Trong C + +, có nhiều lý do để thích tăng thêm so với khác - Tôi tin rằng đó là tiền tăng được khuyến nghị. –

-1

Đối với lớn hơn 0, phải thực hiện hai lần kiểm tra. Nó sẽ kiểm tra nếu bit âm đang tắt và nó sẽ kiểm tra nếu bit không tắt.

Để lớn hơn hoặc bằng không, nó chỉ phải kiểm tra xem bit âm có tắt hay không, bởi vì chúng tôi không quan tâm nếu bit không bật hoặc tắt.

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