2009-06-11 12 views
10

Quay lại ngày tôi làm hầu hết công việc của mình trong C và C++, như một vấn đề áp dụng deMorgan's theorem để tối ưu hóa bất kỳ biểu thức boolean không tầm thường nào.Có hữu ích trong C# để áp dụng định lý DeMorgan để tối ưu hóa các biểu thức boolean theo cách thủ công trong điều kiện có điều kiện (ví dụ: nếu điều kiện)

Có hữu ích khi thực hiện việc này trong C# hay trình tối ưu hóa hiển thị điều này không cần thiết?

Trả lời

31

Trên bộ vi xử lý nhanh, hầu như không thể sắp xếp lại các biểu thức boolean để tạo ra sự khác biệt thực sự về tốc độ. Và trình biên dịch C# rất thông minh, nó cũng sẽ tối ưu hóa nó. Tối ưu hóa cho khả năng đọc và rõ ràng!

+6

+1. Tôi thường xuyên tối ưu hóa các thử nghiệm boolean trong mã của tôi, đặc biệt cho khả năng đọc. – Cheeso

+0

Trình biên dịch? Thông minh? – Kekoa

+4

Trình biên dịch không thể tối ưu hóa logic của các biểu thức mà không gây ra việc đánh giá vào các thời điểm khác nhau. Xem câu trả lời của firoso. Nó có thể đủ thông minh để biết khi nào nó không đủ thông minh. – Kekoa

3

Tôi đoán trình biên dịch sẽ thực hiện điều đó. Bạn có thể làm bài kiểm tra và xem IL đã biên dịch thông qua Reflector.

Tối ưu hóa khả năng đọc và bảo trì. Hãy tự hỏi liệu bạn có hiểu được tối ưu hóa thông minh của mình trong một năm không và nếu bạn nghĩ, mã có thể sử dụng một số nhận xét, làm cho mã tự ghi tài liệu.

2

Đảm bảo tính dễ đọc và bảo trì. Nếu bạn có một bộ các biểu thức boolean khá phức tạp khó đọc, thì Deorm của DeMorgan có thể là một cách tiếp cận tuyệt vời để giảm biểu thức thành một cái gì đó dễ đọc/duy trì hơn nhưng vẫn hợp lệ/phù hợp với nguyên gốc.

Nếu mặt khác, biểu thức chi tiết hơn dễ đọc và giảm biểu thức dễ dàng hơn nhiều, trong khi cân bằng hợp lý, làm cho khó hiểu hơn, hãy để nguyên.

8

Mục tiêu đầu tiên của bạn phải là tối ưu hóa các câu lệnh như vậy để hiểu nhà phát triển và dễ bảo trì.

Định lý DeMorgan có thể là một công cụ hữu ích cho việc này.

7

Tối ưu hóa trong JIT, ở dạng hiện tại của nó, không (từ những gì tôi đã đọc) tối ưu hóa điều này cho bạn. Nếu bạn cần tối ưu hóa nó, bạn sẽ vẫn cần tính đến điều này.

Điều đó đang được nói, đây là một tối ưu hóa vi mô khá nhỏ. Nói chung, tôi muốn viết "các biểu thức boolean không tầm thường" của bạn theo một dạng biểu cảm hơn để chúng dễ hiểu hơn. Với tôi, điều này có giá trị hơn bất kỳ sự tối ưu hóa rất nhỏ nào bạn sẽ nhận được từ việc áp dụng định lý deMorgan.

2

Trong hầu như tất cả các trường hợp thực tế tôi có thể nghĩ đến, việc sắp xếp các toán tử logic không có ảnh hưởng đáng kể đến hiệu năng tổng thể. Nếu chương trình của bạn chờ cơ sở dữ liệu, mạng vv sẽ tốn nhiều thời gian hơn so với các hoạt động nhỏ bé đó. Nếu bạn viết một chương trình mà nó thực sự tạo ra sự khác biệt, tốt hơn hãy bỏ qua C# và sử dụng C++ thay vào đó.

+2

ví dụ truy cập là 'fnThatHitsDB && flagVar' C# sẽ nhấn db trước khi nó kiểm tra biến cục bộ. – BCS

1

Tôi đồng ý với tuyên bố chung rằng tính dễ đọc và khả năng bảo trì là quan trọng nhất khi nói đến tối ưu hóa biểu thức boolean những ngày này. Do đó, định lý của DeMorgan nói chung rất hữu ích.

Có một ngoại lệ đối với quy tắc này. Nếu biểu thức boolean thay đổi biểu thức được tối ưu hóa Định lý của Demorgan, nó có thể khó duy trì hơn. Xem xét một biểu thức với một số đầu vào đã được tối ưu hóa để chỉ hiển thị một vài điều kiện boolean. Một thay đổi đối với logic boolean bắt buộc có thể buộc một người nào đó phải liệt kê ra tất cả các kết hợp boolean có thể có và sau đó reoptimize. Nếu biểu thức được để lại ở định dạng không được tối ưu hóa, một thay đổi sẽ mất ít bước hơn để hoàn thành.

Từ quan điểm giai thoại, tôi tự hỏi nếu giáo dục một nhóm về Định lý DeMorgan và Bản đồ Karnaugh, v.v ... sẽ làm giảm các biểu thức boolean không cần thiết/không hiệu quả. Có lẽ nếu ai đó có hiểu biết tốt về các phương pháp này, anh ta/cô ấy sẽ có xu hướng tạo ra những biểu hiện tốt hơn. Ví dụ, tôi vừa đi qua biểu thức boolean này trong mã của phần mềm tôi duy trì:

if ({boolean variable} != true && false) 
+1

Ai đã viết chưa sẵn sàng cho de Morgan và Karnaugh. Hãy lấy những điều ngu xuẩn cơ bản ra khỏi con đường, và sau đó viết cho dễ đọc. –

+0

Yikes! Tôi cho rằng "&& false" có thể được bỏ qua logic gỡ lỗi ('tạm thời' đảm bảo rằng nếu khối không được thực hiện), nhưng nó đáng ngạc nhiên như thế nào thường xuyên bạn chạy trên cruft như thế này. –

7

Tôi tin rằng câu trả lời đúng cho câu hỏi này là trình biên dịch không (thường) tối ưu hóa đánh giá boolean, đơn giản là do để ngắn mạch logic, ví dụ:

if (GetFlagA() || GetFlagB()) 
{ 
    ...do something 
} 

Trình tự rằng nếu đánh giá thực sự có thể quan trọng nếu gọi GetFlagA đổi cái gì đó GetFlagB dựa trên (cấp này là thực tế đang thực sự xấu, nhưng đó là một chủ đề khác nhau cho một khác nhau thread.) Vấn đề ở đây là logic ngắn mạch, nếu GetFlagA chạy và trả về true, Get FlagB sẽ không bao giờ chạy, như đã thấy ở đây kết quả của GetFlagB là không quan trọng đối với việc đánh giá tuyên bố.

A | B | =

F | F | F

F | T | T

T | F | T đúng bất kể giá trị trả về của B.

T | T | T đúng bất kể giá trị trả về của B.

Tóm lại, hãy hỏi xem bạn có thể tối ưu hóa bằng cách sử dụng Demorgan hay bất kỳ thứ gì thực sự giống như phần còn lại của khoa học máy tính và kỹ nghệ phần mềm. "Nó phụ thuộc." nếu bạn đang sử dụng đánh giá phi chức năng, nó có thể được tối ưu hóa. Thành thật mà nói bạn đang nói một vài hoạt động trên một nền tảng điên rồ nhanh chóng, bạn nên tốt hơn chi tiêu thời gian của bạn bằng văn bản tài liệu.

Tôi hy vọng điều này sẽ hữu ích.

+1

Demorgan không nên thay đổi việc thực hiện. Bởi vì logic được lật xung quanh. ! (! A &&! B) vẫn chỉ thực thi B nếu A sai. –

+0

@BenjaminAutin Tôi đã tự hỏi về điều đó. Là hành vi mà bạn mô tả điển hình trong hầu hết các ngôn ngữ mà thực hiện ngắn mạch, hoặc duy nhất để C#? –

+0

Nên, một khi kết quả cuối cùng được thiết lập, tại sao làm bất kỳ công việc nhiều hơn cần thiết? –

3

Thời gian duy nhất bạn nên làm sắp xếp lại, đại số boolean hoặc demorgan là khi logic quá phức tạp để thực hiện theo cách khác. Nếu nó không quá phức tạp, hãy giữ cho nó có thể đọc được. Có một trường hợp để đơn giản hóa logic.

Thỉnh thoảng khi logic phức tạp, tôi cần tạo một Karnaugh Map để đơn giản hóa logic xuống một thứ mà tôi thậm chí có thể viết ra. Thông thường, việc sử dụng K-Maps có thể giúp bạn tìm ra những cách ngắn gọn hơn để thể hiện logic của bạn. Kết quả có thể hoặc có thể không có ý nghĩa, nhưng nó sẽ là tương đương. Và tôi cũng muốn nói rằng chính DeMorgan thực sự không phải là một sự tối ưu hóa sẽ tạo ra sự khác biệt, Nếu hơn một nửa số hạng là tiêu cực (NOT), bạn sẽ đạt được hiệu suất cao nhất trong việc loại bỏ một số NOT, đó là một lệnh duy nhất cho một CPU trên mỗi NOT. Tệ nhất, bạn có thể thêm nhiều NOTs khi bạn lấy đi, và nếu bạn không nên sử dụng DeMorgan, bạn sẽ nhận được nhiều NOTs hơn bạn đã có ở nơi đầu tiên.

Nếu bạn định tối ưu hóa logic, hãy sử dụng một số đại số boolean hoặc số yêu thích cá nhân của tôi K-Maps để giảm số lượng cụm từ (nếu có thể). Không chỉ di chuyển các toán tử boolean xung quanh, nó ngớ ngẩn.

0

Thỏa thuận đầu tiên với khả năng bảo trì và high-level optimization.

Sau đó, xử lý tối ưu hóa cấp thấp.

2

DeMorgan có thể hoàn toàn không liên quan khi có đánh giá ngắn mạch.

return !(exp1 || exp2); 
return !exp1 && !exp2; 

được biên soạn để

if( exp1) return !(true); else return !(exp2); 
if(!(!exp1)) return false; else return !(exp2); 

với not s hủy và hằng gấp, đây là giống hệt nhau.

Trường hợp quan trọng hơn là thứ tự đánh giá; đặt những thứ bíp có khả năng kích hoạt các mạch ngắn ở phía trước biểu thức. Trình biên dịch không thể tối ưu hóa này cho bạn vì nó là khó khăn cho nó để phát hiện các vấn đề ngữ nghĩa như tác dụng phụ hoặc nếu biểu hiện sau làm cho các giả định dựa trên những người trước đó:

return validState() && checkAssumuingValidState(); 
0

Đối với tất cả chúng ta không CS chuyên ngành:

wikipedia on De Morgan's laws:

luật De Morgan những quy tắc liên quan các toán tử logic "và" và "hoặc" về nhau thông qua phủ định, cụ thể là:

NOT (P HOẶC Q) = (KHÔNG P) AND (NOT Q)
NOT (P và Q) = (KHÔNG P) OR (KHÔNG Q) luật

0

De Morgan là hữu ích cho việc giảm nó đến một hình thức bình thường, ví dụ Dạng không bình thường (DNF) hoặc dạng thông thường liên kết (CNF). Về cơ bản điều này có nghĩa rằng nó là một trong hai

DNF: (a, b và c) OR (đ, e và g) ...

hoặc

CNF: (a hoặc b hoặc c) VÀ (e hoặc f hoặc g) ....

Bạn có thể ném NOT ở mức thấp nhất.

Tôi đồng ý với các áp phích trước đó mà bạn nên tối ưu hóa để dễ đọc và dễ hiểu.

1

Trình tối ưu hóa C# không thể thực sự làm quá nhiều cho các quy tắc ngắn mạch để đánh giá biểu thức logic. Vì vậy, việc áp dụng Luật của DeMorgan sẽ không làm được gì nhiều trừ khi nó cho phép bạn thấy các phép tái cấu trúc hữu ích khác (và dĩ nhiên nó có thể giúp làm cho mã của bạn rõ ràng hơn).

Nhưng có những trường hợp bạn có thể thực hiện các cải tiến hiệu suất đáng kể với các loại tối ưu hóa khác. Ví dụ: các điều kiện này cần được hoán đổi

if (costly_boolean_function() && cheap_often_false_boolean_function()) 

Trình tối ưu hóa truy vấn SQL thực hiện điều này như là một vấn đề, vì SQL không có đoản mạch. Trình tối ưu hóa truy vấn sẽ sắp xếp lại các biến vị ngữ mệnh đề WHERE (của mẫu c1 AND c2 AND ... cn) để đặt các điều kiện ít tốn kém nhất trước, vì chúng có thể đánh giá sai và làm giảm nhu cầu đánh giá các giá trị đắt tiền hơn.

3

Từ biểu thức boolean đánh giá sử dụng ngữ nghĩa phím tắt, bạn có thể di chuyển subexpressions đó là rẻ hơn để tính toán vào phía trước:

if (CountAllFilesOnDrive('C:\') > 7 && useFileScan) { ... } 

sẽ chạy cuộc gọi đắt bất cứ lúc nào expresison được ewvaluated, ngay cả khi nó không phải là cần thiết . Quay xung quanh tuyên bố rằng bỏ qua việc kiểm tra hồ sơ nếu useFileScan là sai:

if (useFileScan && CountAllFilesOnDrive('C:\') > 7) { ... } 

DeMorgan có thể giúp bạn di chuyển "thoát sớm" vào phía trước, và do đó có được hiệu suất trung bình tốt hơn.

Lưu ý rằng do bảo đảm đánh giá từ trái sang phải, trình tối ưu hóa không có nhiều quyền tự do để sửa đổi biểu thức.

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