2010-10-26 14 views
13

là gì đúng trình tự của các hoạt động toán trong biểu thức này trong Java là gì:các ưu tiên bên phải của biểu thức toán học

a + b * c/(d - e) 
1. 4 1 3  2 
2. 4 2 3  1 

tôi hiểu kết quả đó là như nhau trong cả hai câu trả lời. Nhưng tôi muốn hiểu đầy đủ về logic trình biên dịch java. Điều gì được thực thi đầu tiên trong ví dụ này - phép nhân hoặc biểu thức trong dấu ngoặc đơn? Một liên kết đến tài liệu bao gồm điều đó sẽ hữu ích.

CẬP NHẬT: Cảm ơn các bạn đã trả lời. Hầu hết các bạn viết rằng biểu thức trong ngoặc đơn được đánh giá đầu tiên. Sau khi xem các tài liệu tham khảo do Grodriguez cung cấp, tôi đã tạo ra các bài kiểm tra nhỏ:

int i = 2; 
System.out.println(i * (i=3)); // prints '6' 
int j = 2; 
System.out.println((j=3) * j); // prints '9' 

Ai có thể giải thích tại sao các thử nghiệm này tạo ra các kết quả khác nhau? Nếu biểu thức trong dấu ngoặc đơn được đánh giá đầu tiên tôi sẽ mong đợi cùng một kết quả - 9.

+1

Không có câu trả lời nào trong số những câu trả lời này trả lời câu hỏi của anh ấy, bởi vì anh ấy hỏi về dấu ngoặc đơn; chúng không được bao gồm trong tài liệu ưu tiên. Cần lưu ý rằng điều này là tốt nhất được hỏi theo cách này: Các biểu thức parenthetical được đánh giá đầu tiên, hoặc chúng được đánh giá khi cần thiết? Nếu được đánh giá đầu tiên, (2) sẽ chính xác ... nếu được đánh giá khi cần (lười), thì (1) sẽ chính xác. tôi không biết câu trả lời, nhưng có lẽ điều này sẽ giúp ích cho bạn. –

+0

@Myrddin: bạn nói đúng. Đó là tôi có nghĩa là đặt câu hỏi. – bancer

+0

"Đánh giá quy tắc". C.f. câu trả lời đã chỉnh sửa của tôi. –

Trả lời

10

Hầu như tất cả mọi người cho đến nay đã nhầm lẫn thứ tự đánh giá với quyền ưu tiên của nhà điều hành. Trong Java các quy tắc ưu tiên thực hiện các biểu thức tương đương như sau:

a + (b * c)/(d - e) 

*/ có ưu tiên như nhau và còn lại kết hợp.

Thứ tự đánh giá được xác định đúng là left hand operand first, then right, then operation (ngoại trừ || và & &). Vì vậy, thứ tự đánh giá là:

a 
     b 
     c 
    * 
     d 
     e 
    - 
/
+ 

thứ tự đánh giá sẽ đi xuống trang. Thụt đầu dòng phản ánh cấu trúc của cây cú pháp

Sửa

Đáp lại ý kiến ​​của Grodriguez.Các chương trình sau đây:

public class Precedence 
{ 
    private static int a() 
    { 
     System.out.println("a"); 
     return 1; 
    } 
    private static int b() 
    { 
     System.out.println("b"); 
     return 2; 
    } 
    private static int c() 
    { 
     System.out.println("c"); 
     return 3; 
    } 
    private static int d() 
    { 
     System.out.println("d"); 
     return 4; 
    } 
    private static int e() 
    { 
     System.out.println("e"); 
     return 5; 
    } 

    public static void main(String[] args) 
    { 
     int x = a() + b() * c()/(d() - e()); 
     System.out.println(x); 
    } 
} 

Tạo đầu ra

a 
b 
c 
d 
e 
-5 

trong đó cho thấy rõ nhân được thực hiện trước khi các phép trừ.

+1

"Việc triển khai ngôn ngữ lập trình Java phải tôn trọng thứ tự đánh giá như được biểu thị rõ ràng bằng dấu ngoặc đơn và ngầm định bởi quyền ưu tiên của toán tử". (JLS, 15.7.3) – Grodriguez

+0

@Grodriguez: "Toán hạng bên trái của toán tử nhị phân xuất hiện để được đánh giá đầy đủ trước khi * bất kỳ phần * nào của toán hạng bên phải được đánh giá." (JLS 15.7.1). [nhấn mạnh]. Thứ tự đánh giá trong ví dụ của tôi hoàn toàn phù hợp với 15.7.3. – JeremyP

+1

@JeremyP Wow, tôi đã viết chính xác chương trình đó để chứng minh cho bản thân mình rằng tôi đã đúng. – ILMTitan

12

Vì JeremyP có độc đáo shown us, câu trả lời đầu tiên là chính xác.

Nói chung, các quy tắc sau được áp dụng:

  • Mỗi toán hạng của một nhà điều hành được đánh giá trước khi phẫu thuật riêng của mình được thực hiện (trừ ||, &&, và ?:)
  • Phép toán được đánh giá trái sang đúng. Toán hạng bên trái của toán tử nhị phân xuất hiện để được đánh giá đầy đủ trước khi bất kỳ phần nào của toán hạng bên phải được đánh giá.
  • Trình tự đánh giá tôn trọng ngoặc đơn và khai thác được ưu tiên:
    • ngoặc được đánh giá đầu tiên.
    • Nhà điều hành được đánh giá theo thứ tự ưu tiên.
    • Các toán tử có mức độ ưu tiên bằng nhau được đánh giá từ trái sang phải, ngoại trừ các toán tử gán được đánh giá từ phải sang trái.

Lưu ý rằng hai nguyên tắc đầu tiên giải thích kết quả trong câu hỏi thứ hai của bạn:

int i = 2; 
System.out.println(i * (i=3)); // prints '6' 
int j = 2; 
System.out.println((j=3) * j); // prints '9' 

tài liệu tham khảo:

http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#4779

Hướng dẫn:

http://download.oracle.com/javase/tutorial/java/nutsandbolts/operators.html

+0

+1 cho liên kết đầu tiên – bancer

+0

Mô tả này là chính xác về kết quả được tạo cho biểu thức, nhưng không phải luôn luôn đúng khi nói "dấu ngoặc đơn được đánh giá đầu tiên". Nếu bất kỳ thứ nào trong ngoặc đơn là các phương thức thì điều này có thể là quan trọng. – DJClayworth

+1

Câu trả lời thứ hai là không chính xác. '*' và '/' có cùng một giá trị và được liên kết trái. Do đó, biểu thức tương đương với 'a + ((b * c)/(d - e))'. Cùng với quy tắc để lại toán hạng được đánh giá đầu tiên, có nghĩa là 'b * c' được đánh giá đầu tiên. – JeremyP

0

tôi đang giả định rằng biểu hiện của bạn sẽ là một cái gì đó giống như

x = a + b * c/(d - e)

các nhà điều hành bình đẳng có quyền tự bên trái của đánh giá. do đó, biểu thức bên phải của = sẽ được đánh giá đầu tiên.

nếu bạn tham khảo biểu đồ ưu tiên này: http://www.java-tips.org/java-se-tips/java.lang/what-is-java-operator-precedence.html

1) khung sẽ được đánh giá (de), cho phép nói (de) = f để biểu thức sau đó trở thành x = a + b * c/f.

2) Bây giờ * và/có cùng quyền ưu tiên, nhưng thứ tự đánh giá là trái sang phải * sẽ được đánh giá đầu tiên, vì vậy hãy nói b * c = g, vì vậy biểu thức trở thành x = a + g/f

3) Bây giờ/có ưu tiên tiếp theo để g/f sẽ được đánh giá để cho phép nói h nên biểu sẽ được đến x = a + h,

4) cuối cùng đánh giá a + h

+0

* toán tử bình đẳng *? Ý bạn là * toán tử gán *. –

-1

các kết quả tính toán được xác định bởi Operator Order of Precedence. Vì vậy, dấu ngoặc đơn có ưu tiên cao nhất ở đây, nhân và chia cao nhất tiếp theo, và cộng và trừ thấp nhất. Các toán tử có quyền ưu tiên bằng nhau được đánh giá từ trái sang phải. Vì vậy, biểu thức trong câu hỏi tương đương với:

a + (b * c)/(d - e)) 

Tuy nhiên, có sự khác biệt nhỏ giữa ý nghĩa bình thường của "được đánh giá đầu tiên" và nhà điều hành để nhận câu trả lời đúng.

"d-e" không nhất thiết phải được tính toán trước khi "a" được tính. Điều này khá nhiều không thực hiện bất kỳ sự khác biệt trừ khi một trong những 'biến' trong biểu thức thực sự là một chức năng. The Java standard does not specify the order of evaluation of components of an expression.

+2

Văn bản liên kết của bạn dường như bị mâu thuẫn với văn bản liên kết đến. Nó chỉ bao gồm một hướng dẫn phong cách cho thấy sự phụ thuộc quá nhiều có thể gây ra mã khó hiểu. – ILMTitan

-1
a + b * c/(d - e) 
     1   1 
      2 
    3 

Toàn bộ điểm ưu tiên của toán tử là chuyển đổi biểu thức thành cây cú pháp. Ở đây, *- ở cùng cấp độ của cây. Cái nào được đánh giá trước là không liên quan đến kết quả và không được bảo hành .

Chỉnh sửa: Xin lỗi, tôi đã nhầm lẫn với nền C của mình. Như những người khác đã chỉ ra, Java có một quy tắc "Đánh giá toán tử bên trái đầu tiên". Áp dụng quy tắc này cho / cho bạn biết rằng * được đánh giá trước tiên (câu trả lời đầu tiên của bạn).

+0

Có * và/không cùng mức độ ưu tiên không? Có lý do nào để tin rằng nó sẽ làm phép nhân trước khi phân chia hay chỉ vì trái sang phải đặt dấu * trước/ – Chris

+0

Java thi hành từ trái qua phải cho các toán tử có cùng mức ưu tiên. – Grodriguez

+0

Từ [Đặc tả Java] (http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#239829): "[*,/và%] có cùng mức độ ưu tiên và là liên kết trái cú pháp (chúng nhóm từ trái sang phải). " –

4

Nó đánh giá các biểu thức theo thứ tự sau. Tên biến là các biểu thức cần được đánh giá.

a + b * c/(d - e) 
    2 3 5 6 
     4  7 
1   8 
    9 

Vì vậy, câu trả lời cho câu hỏi của bạn là # 1. Thứ tự của các hoạt động xác định hình dạng của cây biểu hiện (phía bên trái của cây là gì, và bên phải là gì), nhưng bên trái luôn được đánh giá đầu tiên (và gốc được đánh giá lần cuối).

+0

+1 để kiểm tra câu trả lời chống lại thực tế :) – JeremyP

0

Trong câu hỏi thứ hai của bạn, có vẻ như Java đang đánh giá phần trong dấu ngoặc đơn như một bài tập, không phải là một biểu thức toán học. Điều này có nghĩa là sẽ không thực hiện các phép gán cha mẹ theo thứ tự giống như các phép toán trong dấu ngoặc đơn.

+1

Bài tập ** là ** biểu thức! –

1

Tôi sẽ tưởng tượng rằng nó có thể đánh giá một cái gì đó như thế này đánh giá từ trái sang phải.

a + b * c/(d-e)

Action   Left Value  Right Value 
Start Add  a    b*c/(d-e) 
Start Multiply b    c 
Calc Multiply (since it can)  
Start Divide  b*c    (d-e) 
Start Subtract d    e 
Calc Subtract 
Calc Divide 
Calc Add 

này có thể được coi là tạo ra một cây nhị phân đại diện cho các tính toán và sau đó làm việc kể từ nút lá, trái sang phải, tính toán mọi thứ. Đáng tiếc là nghệ thuật ascii của tôi là không lớn nhưng đây là một nỗ lực nhằm đại diện cho cây trong câu hỏi:

Add 
    /\ 
/\ 
    a \ 
    Divide 
    /\ 
    / \ 
    / \ 
    /  \ 
Multiply Subtract 
    /\   /\ 
/\  /\ 
b c  d e 

Và tôi đã làm một số xét nghiệm trong C# (Tôi biết nó không giống nhau nhưng đó là nơi quyền lợi của tôi nói dối và các bài kiểm tra thể thể dễ dàng thích nghi) như sau:

 f = 1; 
     Console.WriteLine((f=2) + (f) * (f)/((f) - (f)-1)); 
     Console.WriteLine(2 + 2 * 2/(2 - 2 - 1)); 
     f = 1; 
     Console.WriteLine((f) + (f=2) * (f)/((f) - (f)-1)); 
     Console.WriteLine(1 + 2 * 2/(2 - 2 - 1)); 
     f = 1; 
     Console.WriteLine((f) + (f) * (f = 2)/((f) - (f)-1)); 
     Console.WriteLine(1 + 1 * 2/(2 - 2 - 1)); 
     f = 1; 
     Console.WriteLine((f) + (f) * (f)/((f=2) - (f)-1)); 
     Console.WriteLine(1 + 1 * 1/(2 - 2 - 1)); 
     f = 1; 
     Console.WriteLine((f) + (f) * (f)/((f) - (f=2)-1)); 
     Console.WriteLine(1d + 1d * 1d/(1d - 2d - 1d)); 

các cặp câu Console.WriteLine là một đại số (sử dụng các thiết lập một thủ thuật số) và trình bày bằng số hiển thị những gì tính toán thực hiện. Các cặp tạo ra kết quả giống nhau.

Có thể thấy các đối số được đánh giá theo thứ tự bất kỳ sau khi gán được 2 và trước khi là một. Vì vậy, thứ tự đánh giá của mọi thứ đơn giản từ trái sang phải, tôi nghĩ nhưng thứ tự tính toán như bạn mong đợi.

Tôi giả định này có thể chạy gần như với sao chép và dán để kiểm tra trong JAVA ...

Có thể có một số giả định không được chú ý ở đây vì vậy nếu ai làm sai sót chỗ logic trong đây xin đừng gọi tôi vào chúng và Tôi sẽ làm việc thông qua.

+0

Cây của bạn sai. Nhân nên được bên trái dưới Divide. Hãy thử trường hợp trong đó b = 20, c = 1, d = 20 và e = 0. – ILMTitan

+0

Không, Chris, đó là 'a + (b * c)/(d-e)', không phải 'a + b * (c/(d-e))'. Bởi vì *,/và% có liên kết trái. –

+0

ILMTitan: Có lẽ là những con số và sử dụng số nguyên sao cho c/(d-e) sẽ bị cắt ngắn về 0 cho thấy sự khác biệt. Tôi đã không thử nó trong mã nhưng tôi thấy nó sẽ hoạt động như thế nào. :) Edgar Bonet: OK, yup. Tôi hiểu ý bạn là gì. Đã không thực sự spec kiểm tra đủ có vẻ như. Khán giả lý do rằng có một quy tắc. :) Tôi sẽ cập nhật nghệ thuật ascii tuyệt vời của tôi ... ;-) – Chris