2012-01-18 22 views
11

Khi so sánh với tối thiểu hoặc tối đa hai số/chức năng, C# có ngắn mạch nếu trường hợp này đúng với trường hợp đầu tiên và có ngụ ý sự thật cho số thứ hai không? Ví dụ cụ thể các trường hợp này làKhông so sánh với ngắn mạch Math.Min hay Math.Max?

if(x < Math.Max(y, z())) 

if(x > Math.Min(y, z())) 

Kể từ Math.Max(y, z()) sẽ trả về một giá trị ít nhất là lớn như y, nếu x < y thì không có nhu cầu để đánh giá z(), mà có thể mất một lúc. Tình huống tương tự với Math.Min.

Tôi nhận ra rằng những thể cả hai được viết lại dọc theo dòng của

if(x < y || x < z()) 

để ngắn mạch, nhưng tôi nghĩ rằng đó là rõ ràng hơn những gì mà so sánh là không viết lại. Điều này có ngắn mạch không?

+3

Giả sử bạn gọi 'if (x> XYZ (y, z()))' Làm thế nào trình biên dịch có thể biết kết quả của XYZ? Max, Min, Average hoặc bất cứ điều gì khác? –

+0

@ L.B Điểm tuyệt vời, tôi đã không xem xét điều này theo cách đó. – yoozer8

+0

Ngoài ra, biểu thức "ngắn mạch" có thể không tương đương, tùy thuộc vào cách 'Min' và' Max' xử lý NaN. – dan04

Trả lời

18

Như những người khác đã chỉ ra, trình biên dịch không biết gì về ngữ nghĩa của Min hoặc Max cho phép nó phá vỡ quy tắc mà đối số được đánh giá trước khi phương thức được gọi.

Nếu bạn muốn viết của riêng bạn, bạn có thể làm như vậy một cách dễ dàng đủ:

static bool LazyLessThan(int x, int y, Func<int> z) 
{ 
    return x < y || x < z(); 
} 

và sau đó gọi nó

if (LazyLessThan(x, y, z)) 

hoặc

if (LazyLessThan(x, y,()=>z())) 

Hoặc cho rằng vấn đề:

static bool LazyRelation<T>(T x, T y, Func<T> z, Func<T, T, bool> relation) 
{ 
    return relation(x, y) || relation(x, z()); 
} 
... 
if (LazyRelation(x, y,()=>z, (a,b)=> a < b))) 
+0

Đó ví dụ cuối cùng sẽ là rất lớn, nếu có thể để thêm một đối số mặc định, như vậy: static bool LazyRelation (T x, T y, Func x, Func mối quan hệ = (a, b) => a zmbq

+3

+1 Câu trả lời hay, nhưng hãy trung thực - tất cả đều có thể đọc được/duy trì hơn 'if (x Yuck

+0

Tôi muốn nói nó ít dễ đọc hơn, bởi vì nó thay thế thành ngữ cơ bản bằng một hàm có định nghĩa bạn phải đọc để hiểu mã. –

10

Không, không ngắn mạch và z() sẽ luôn được đánh giá. Nếu bạn muốn các hành vi ngắn mạch bạn nên viết lại như bạn đã làm.

+4

Lý do cho điều này là do thời gian chạy không có cách nào để biết những tác động của 'Max()' và 'Min()' là gì. ** Bạn ** làm, cho phép bạn viết lại theo cách hiệu quả hơn. – Yuck

2

Không, nó không ngắn mạch, ít nhất là ở mức trình biên dịch C#. Math.Min hoặc Math.Max là hai cuộc gọi phương thức tĩnh thông thường và trình biên dịch sẽ không tối ưu hóa theo nghĩa đó.

Trình tự đánh giá của mã sẽ là: z(), Math.max, x> ...

Nếu bạn thực sự muốn chắc chắn, hãy kiểm tra mã IL.

5

Math.Min()Math.Max() là các phương pháp giống như bất kỳ phương pháp nào khác. Chúng phải được đánh giá để trả về giá trị sẽ được sử dụng làm đối số thứ hai trong so sánh. Nếu bạn muốn ngắn mạch sau đó bạn sẽ phải viết điều kiện bằng cách sử dụng các nhà điều hành || như bạn đã chứng minh.

3

(Không có gì đặc biệt mới để thêm, nhưng tôi figured tôi muốn chia sẻ kết quả của một thử nghiệm tôi chạy trên nó.)

Math.max() có thể dễ dàng được inlined bởi just-in-time trình biên dịch của CLR và từ đó tôi đã tò mò liệu nó có thể tiếp tục tối ưu hóa mã theo cách mà nó được lưu thông ngắn hay không.

Vì vậy, tôi đã đánh dấu một microbenchmark đánh giá hai biểu thức 1.000.000 lần mỗi lần. Đối với z(), tôi đã sử dụng một hàm tính Fib (15) sử dụng phương thức đệ quy. Đây là kết quả của việc chạy hai:

x < Math.Max(y, z()) : 8097 ms 
x < y || x < z()  :  29 ms 

Tôi đoán CLR sẽ không chuyển đổi mã theo bất kỳ cách nào ngăn chặn cuộc gọi phương thức thực thi, vì nó không biết (và không kiểm tra để xem liệu) thói quen có bất kỳ tác dụng phụ nào không.

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