Каков правильный приоритет математического выражения
Какова правильная последовательность математических операций в этом выражении в Java:
a + b * c / ( d - e )
1. 4 1 3 2
2. 4 2 3 1
Я понимаю, что в обоих ответах результат одинаковый. Но я хотел бы полностью понять логику компилятора java. Что выполняется первым в этом примере - умножение или выражение в круглых скобках? Ссылка на документацию, которая охватывает это, будет полезна.
ОБНОВЛЕНИЕ: Спасибо, ребята, за ответы. Большинство из вас пишут, что выражение в круглых скобках сначала оценивается. Изучив ссылки, предоставленные Гродригесом, я создал небольшие тесты:
int i = 2;
System.out.println(i * (i=3)); // prints '6'
int j = 2;
System.out.println((j=3) * j); // prints '9'
Может ли кто-нибудь объяснить, почему эти тесты дают разные результаты? Если выражение в круглых скобках оценивается первым, я ожидаю тот же результат - 9.
Ответы
Ответ 1
Почти все до сих пор путали порядок оценки с приоритетом оператора. В Java правила приоритета делают выражение эквивалентным следующему:
a + (b * c) / ( d - e )
поскольку *
и /
имеют одинаковый приоритет и остаются ассоциативными.
Порядок оценки строго определяется как левый операнд сначала, затем правый, затем операция (кроме || и && & &). Таким образом, порядок оценки:
a
b
c
*
d
e
-
/
+
порядок оценки идет по странице. Отступ отражает структуру дерева синтаксиса
Edit
В ответ на комментарии Гродригеса. Следующая программа:
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);
}
}
Производит вывод
a
b
c
d
e
-5
который ясно показывает, что умножение выполняется до вычитания.
Ответ 2
Как показал нам JeremyP , первый ответ правильный.
В общем случае применяются следующие правила:
- Каждый операнд оператора вычисляется до выполнения самой операции (кроме
||
, &&
и ?
:
)
- Операнды оцениваются слева направо. Левый операнд двоичного оператора оказывается полностью оцененным до того, как будет оценена любая часть правого операнда.
- Порядок оценки соответствует скобкам и приоритету оператора:
- Сначала оцениваются скобки.
- Операторы оцениваются в порядке приоритета.
- Операторы с одинаковым приоритетом оцениваются слева направо, за исключением операторов присваивания, которые оцениваются справа налево.
Обратите внимание, что первые два правила объясняют результат в вашем втором вопросе:
int i = 2;
System.out.println(i * (i=3)); // prints '6'
int j = 2;
System.out.println((j=3) * j); // prints '9'
Справочная документация:
http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#4779
Учебник:
http://download.oracle.com/javase/tutorial/java/nutsandbolts/operators.html
Ответ 3
Он вычисляет выражения в следующем порядке. Имена переменных - это выражения, которые необходимо оценить.
a + b * c / (d - e)
2 3 5 6
4 7
1 8
9
Итак, ответ на ваш вопрос - №1. Порядок операций определяет форму дерева выражений (то, что является левой стороной дерева, и что является правильным), но сначала левая сторона всегда оценивается (и корень оценивается последним).
Ответ 4
Я бы предположил, что он может оценивать что-то вроде этого, оценивая слева направо.
а + Ь * с/(г-е)
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
Это можно рассматривать как создание двоичного дерева, представляющего вычисления, а затем работу с листовыми узлами, слева направо, вычисление вещей. К сожалению, мое искусство ascii не велико, но вот попытка представить это дерево:
Add
/\
/ \
a \
Divide
/ \
/ \
/ \
/ \
Multiply Subtract
/\ /\
/ \ / \
b c d e
И я сделал несколько тестов на С# (я знаю, что это не то же самое, но где мои интересы лежат и тесты могут быть легко адаптированы) следующим образом:
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));
Пары команд console.writeline являются алгебраическими (с использованием набора трюков числа) и численным представлением, показывающим, что на самом деле делает расчет. Пара производит одинаковый результат, как и каждый другой.
Как можно видеть, аргументы оцениваются по порядку с любым после того, как присваивание равно 2 и до того, как оно будет одним. Поэтому порядок оценки вещей прост в праве, я думаю, но порядок вычислений, как и следовало ожидать, будет таким.
Я предполагаю, что это можно запустить почти с копией и вставкой для тестирования в JAVA...
Здесь могут быть какие-то незаметные предположения, поэтому, если кто-то обнаруживает здесь логические недостатки, пожалуйста, позвоните мне, и я их обработаю.
Ответ 5
Я предполагаю, что ваше выражение будет чем-то вроде
x = a + b * c/(d - e)
оператор равенства имеет право на левый порядок оценки. поэтому сначала будет оценено выражение справа от.
если вы ссылаетесь на этот график приоритета: http://www.java-tips.org/java-se-tips/java.lang/what-is-java-operator-precedence.html
1) скобки будут оцениваться (d-e), скажем (d - e) = f, поэтому выражение тогда становится
x = a + b * c/f.
2) Теперь * и/имеют тот же приоритет, но порядок оценки слева направо на * будет сначала оценен, поэтому скажем b * c = g, поэтому выражение примет вид x = a + g/f
3) Теперь/имеет следующий приоритет, так что g/f будет оцениваться так, чтобы сказать h, чтобы выражение получилось x = a + h,
4), наконец оценивая a + h
Ответ 6
В вашем втором вопросе кажется, что Java оценивает часть в скобках как назначение, а не математическое выражение. Это означает, что это не будет выполнять скобки в том же порядке, что и операции в скобках.
Ответ 7
Результаты расчета определяются Оператором порядка приоритета. Таким образом, скобки имеют наивысший приоритет здесь, умножение и деление, следующие самые высокие, и сложение и вычитание наименьшее. Операторы с одинаковым приоритетом оцениваются слева направо. Таким образом, выражение в вопросе эквивалентно выражению:
a + (b * c) / ( d - e ))
Однако существует небольшая разница между тем, что обычно подразумевается под "оценкой сначала" и приоритетом оператора для получения правильного ответа.
"d-e" не обязательно вычисляется до вычисления "a". Это в значительной степени не имеет никакого значения, если только одна из "переменных" в выражении фактически является функцией. В стандарте Java не указывается порядок оценки компонентов выражения.
Ответ 8
a + b * c / ( d - e )
1 1
2
3
Весь смысл приоритета оператора состоит в том, чтобы преобразовать выражение в дерево синтаксиса. Здесь *
и -
находятся на одном уровне дерева. Какой из них оценивается первым, не имеет значения для результата и не гарантируется.
Изменить. Извините, меня смутил мой фон. Как указывали другие, в Java есть правило "Оценить левый операнд первым". Применение этого правила к /
говорит вам, что сначала оценивается *
(ваш первый ответ).