Каков правильный приоритет математического выражения - PullRequest
14 голосов
/ 26 октября 2010

Какова правильная последовательность математических операций в этом выражении в 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.

Ответы [ 8 ]

13 голосов
/ 26 октября 2010

Поскольку 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

10 голосов
/ 26 октября 2010

Почти все до сих пор путали порядок вычисления с приоритетом оператора.В Java правила предшествования делают выражение эквивалентным следующему:

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

, потому что * и / имеют равный приоритет и остаются ассоциативными.

Порядок вычисления строгоопределяется как сначала левый операнд, затем правый, затем операция (за исключением || и &&).Таким образом, порядок оценки:

  a
      b
      c
    *
      d
      e
    -
  /
+

порядок оценки идет вниз по странице.Отступы отражают структуру синтаксического дерева

Редактировать

В ответ на комментарии Гродригеса.Следующая программа:

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

, который ясно показывает, что умножение выполнено перед вычитанием.

4 голосов
/ 26 октября 2010

Он вычисляет выражения в следующем порядке. Имена переменных - это выражения, которые необходимо оценить.

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

Итак, ответ на ваш вопрос # 1. Порядок операций определяет форму дерева выражений (что является левой стороной дерева, а что правым), но левая сторона всегда вычисляется первой (а корень - последней).

1 голос
/ 26 октября 2010

Я бы предположил, что это может оценить что-то подобное, оценивая слева направо.

a + b * c / (de)

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

И я провел несколько тестов в C # (я знаю, что это не то же самое, но в этом мои интересы итесты могут быть легко адаптированы) следующим образом:

        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 ...

Здесь могут быть некоторые незамеченные предположения, поэтому, если кто-то обнаружит здесь недостатки логики, пожалуйста, позвонитея на них, и я проработаю их.

0 голосов
/ 26 октября 2010

В вашем втором вопросе кажется, что Java оценивает часть в скобках как присваивание, а не математическое выражение. Это означает, что он не будет выполнять назначения в скобках в том же порядке, что и операции в скобках.

0 голосов
/ 26 октября 2010
a + b * c / ( d - e )
      1         1
          2
  3

Весь смысл приоритета оператора заключается в преобразовании выражения в синтаксическое дерево. Здесь * и - находятся на одном уровне дерева. Какой из них оценивается первым, не имеет значения для результата и не гарантируется .

Редактировать : Извините, меня смутил мой фон C. Как уже отмечали другие, в Java есть правило «Оцените левый операнд первым». Применение этого правила к / говорит о том, что * оценивается первым (ваш первый ответ).

0 голосов
/ 26 октября 2010

Результаты расчета определяются Оператором Порядка приоритета .Таким образом, здесь круглые скобки имеют наивысший приоритет, умножение и деление следуют за наивысшим, а сложение и вычитание - наименьшим.Операторы с одинаковым приоритетом оцениваются слева направо.Таким образом, выражение в вопросе эквивалентно:

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

Однако существует небольшая разница между тем, что обычно понимается как «сначала оценивается», и приоритетом оператора для получения правильного ответа.

«де» не обязательно фактически вычисляется до того, как вычисляется «а».Это в значительной степени не имеет никакого значения, если только одна из «переменных» в выражении не является функцией. Стандарт Java не определяет порядок вычисления компонентов выражения.

0 голосов
/ 26 октября 2010

Я предполагаю, что ваше выражение будет что-то вроде

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

оператор равенства имеет порядок вычисления справа налево. поэтому выражение справа от = будет вычислено первым.

если вы ссылаетесь на эту таблицу приоритетов: http://www.java -tips.org / java-se-tips / java.lang / what-is-java-operator-priordence.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) наконец, оценка + h

...