Как стать автором
Обновить

Комментарии 66

браузеры с вами не согласны (-8
Спасибо, кэп. Сижу, размышляю Оо
Так 8 же. Ничего удивительного.
а как же скобки, они ведь должны первыми выполнятся, ну т.е. выражение в скобках?
Унарные операции имеют приоритет выше, чем умножение и сложение.
Разбор:
b = a++ + (--a * ++a)
Сначала выражение в скобках
*в нём
**сначала унарные операции, затем умножение:
***a = a-- => a = 1
***a = a++ => a = 2
**делаем операцию в скобках (умножение), получаем (2 * 2) = 4
Далее сложение, но сначала унарная операция инкримента
*a = a++ => a = 4
Результат:
4 + 4 = 8
ну нет, тогда должно быть так:
1) выполняется выражение в скобках: --a * ++a
--a уменьшает а на 1 (было 2, стало 1) и возвращает ее значение
++а увеличивает а на 1 (было 1, стало 2) и возвращает ее значение
получается результат (1 * 2)=2
2) а++ + 2
а++ возвращает значение а (сейчас равное 2) и инкрементирует а после операции
2 + 2 = 4

т.е. b=4, а=3 вроде как должно быть ((=
В первом пункте путаница. Сначала декремент до 1, затем инкремент до 2, что сбивает с толку, когда начинаешь умножать: а умножается на а, но а равна 2, стало быть 2*2 =)
Как у вас в результате a++ 4 получилось?
Засыпаю за столом… Вроде max7 правильно написал ниже. С утра точно напишу.
А если записать так
b=(a++) + (--a * ++a)

Всё становится на свои места? А скобки то незначащие :)
если так то да (= т.е. их нет, но они какбы есть?
НЛО прилетело и опубликовало эту надпись здесь
Консоль фаербага выдаёт 8. Как я понимаю
a++ возвращает 2 и увеличивает переменную «a» до 3.
--a уменьшает переменную «a» до 2 и возвращает её
++a увеличивает переменную «a» до 3 и возвращает её
Получается:
2 + (2 * 3)
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
Разве это не странно? Разве не должно быть так:
1) --а = 1
2) ++а = 2
3) 2*1 = 2
4) (а = 2, благодаря инкременту)
5) а++ = 3
6) 3+2 = 5
Выходит что не так =) Похоже приоритет у инкриментов и дикриментов выше чем у операций.
8? лень проверять
или undefined)
var a = 2, b = 0;
b = (a++ + (--a * ++a));
alert(b);

(0) a = 2; | b = (a++ + (--a * ++a));
(1.0) a = 3; | b = (2 + (--a * ++a));
(1.1) a = 2; | b = (2 + (2 * ++a));
(1.2) a = 3; | b = (2 + (2 * 3));
(2) b = 8;
У операторов сначала вычисляется левый операнд затем правый. Для ||, &&, например, это прямо влияет на вычисления следующего операнда.
У операторов приоритет слева направо, а у унарных операций разве не справа налево?
Что у унарных операций может быть справа налево?
НЛО прилетело и опубликовало эту надпись здесь
Не унарная операция, а левый операнд бинарной операции, который, по счастливому совпадению, является инкрементом
В данном случае, да. Извиняюсь, по короче. Представьте себе дерево разбора. В корне +, на левой ветви ++a, на правой (--a * ++a), у неё в свою очередь в корне *, на левой ветви --a, на правой ветви ++a, и т.д. Вычисления идут слева направо — сначала полностью посчитается левая ветвь, затем правая. (см. коммент skel2007 ниже)

Пример можно переписать так:
var a = 2, b = 0, c = 0;
b = ( (c = a, a = c+1, c) + ( (a = a-1, a) * (a = a+1, a) ) )
8, проверил в браузере- 8… я удивлен^^
т.е. не удивительно, что операция () выполняется позже инкремента?
Правила, которым нас учили в первом классе, не работают. Вспомните перестановочность операции сложения.
А теперь посчитайте выражения
a + (++a * ++a)
и
(++a * ++a) + a
Перестановочность? Чушь.

То же самое и с скобками. Не работает правило «что в скобках, то выполняется первым». Здесь скобки лишь указывают, что является операндом какой операции. И a здесь оказывается таким же выражением, обладающим теми же правами.

Если угодно, то объяснить можно так:
1) строится дерево выражения
2) запрашивается значение его вершины
3) при запросе значения любой вершины, соответствующей бинарному операнду, идет подзапрос на ЛЕВУЮ вершину, а после того, как получено ее значение, — подзапрос на ПРАВУЮ

В нашем случае дерево имеет вид:
          +
   .++           *
    a        --.    ++.
              a      a
(Здесь через .++ и ++. обозначаются операции, соответствующие a++ и ++a).

Пользуясь вышеописанными правилами, вполне логично получаем 8.
Правила, которым нас учили в первом классе, не работают. Вспомните перестановочность операции сложения.
А теперь посчитайте выражения
a + (++a * ++a)
и
(++a * ++a) + a
Перестановочность? Чушь.
Не согласен, в этих примерах сложение принимает различные операнды, соответственно коммутативность не нарушается.
алгебра не манипулирует переменными, а только константами.
Простите, но не интересная задачка… Все оказалось как и должно быть…
задачка ради задачки… и точнее пудрения мозгов.
В разработке таких выражений не должно быть.
ну вообще-то ради выяснения приоритета операций в скобках
ок, хорошо, для общего образования новичков, конечно полезно, спорить не буду.
НЛО прилетело и опубликовало эту надпись здесь
1 * (1 + 1)
Скобки не означают, что сначала будет посчитано 1 + 1, они просто говорят, что 1 + 1 — это правый операнд умножения.
Хотя, может, в арабских компиляторах и справа налево считается;)
То, что 1 + 1 воспринимается, как один операнд по отношению к * подразумевает, что он будет вычислен до выполнения умножения. :)
Именно, но до выполнения подсчета левого операнда. ;)
НЕ до, простите.
Левый операнд и не нужно подсчитывать, он и так 1 :)
в нашем случае он a++
Посчитал в уме — получилось 8. В комментариях увидел что так и есть.
В данном случае если скобки убрать должно получится тоже самое. И это правильно.
Скобки позволяют изменить привычный порядок, например
2+2*2 != (2+2)*2

В других случаях скобки роли не играют.
«комментарии (42)» — Хабр как бы говорит нам :)
В С++ для таких случаев есть специальное редкое правило «sequence point», которое определяет как работают операторы с side-effect'ом. К сожалению, джаву я знаю хуже и там их не встречал. Но вполне может быть что они там есть ^_^. Для C++ такой код был бы некорректен (скомпилился бы, но результат compiler specific), так как запрещено использовать в рамках одного sequence point оператор с side effect'ом ( a ++ ) и любой другой оператор, изменяющий значение этой же переменной. Гуру Java, как там в ней с такими изысками?
> var a=2
> b=a++ + (--a * ++a)
> //Чему равно b?

1. Как это решает комп:

Для тех не в курсе дела, пусть посмотрят что такое обратная польcкая запись: ru.wikipedia.org/wiki/%D0%9E%D0%B1%D1%80%D0%B0%D1%82%D0%BD%D0%B0%D1%8F_%D0%BF%D0%BE%D0%BB%D1%8C%D1%81%D0%BA%D0%B0%D1%8F_%D0%B7%D0%B0%D0%BF%D0%B8%D1%81%D1%8C
Итак, расписываем псевдокод разбора выражения, согласно обратной польской записи:
1. встретили a, помещаем в стек операндов значение a
2. встретили ++, увеличиваем a на 1
3. встретили +, помещаем в стек операторов оператор +
4.…
Таким образом расписав, получается верный ответ (лень расписывать до конца на ночь глядя, довольно большой список получится)

2. Как это решает человек, который в читал спеки (человек-комп):

Унарные операторы имеют приоритет над всеми остальными операторами, и вычисляется по мере использования в выражении независимо от наличия скобок.
То есть, определив ход вычисления (что за чем вычисляется), сначала вычисляем унарные, потом — все остальное.
Получаем:
b = a++ + (--a * ++a) = [первый операнд=2, второй=(первый+1)-1, третий=второй+1] = 2+((2+1-1)*(2+1)) = 8

3. Как это решает человек логичный:

Первый ++ компенсируется последующим --, а последний ++ заменяется на a+1, и выражение упрощается:
b = a+a*(a+1) = 2+2*3 = 8
я решал так :)
> var a=2
> b=a++ + (--a * ++a)
> //Чему равно b?
сначала взял скобки (--a * ++a) и пошел справа на лево
2+1 = 3 * 2 = 6 -1 = 5, все что в скобках = 5
5++ = 6 + 2 = 8
итого получилось 8, а все от того, что почему то вспомнил правило, справа на лево :)
откуда это 5++?
там а++, а не скобки++
для простоты вашего понимания
Сначала все выражение будет представлено как сумма двух подвыражений.
Из них первым будет вычислено левое, что даст 2, a станет равно 3.
Затем правое, что даст 2*3 = 6.
После этого они будут сложены, получим 2+6 = 8.
$ python
>>> a=2
>>> print a++ + (--a * ++a)
6


Как-то так.
Исходя из приоритета операций скобки () имеют наивысший приоритет
Тут какая-то путаница.

Скобки — это не оператор и не операция, это явное изменение порядка выполнения.
Приоритеты служат для разбора порядка выполнения в неявном случае.

Если скобки не меняют порядок, то они не должны никак влиять на результат. То есть a+b*c и a+(b*c) должны выдавать одинаковый результат, что бы там под a,b и c не было.
НЛО прилетело и опубликовало эту надпись здесь
C и Javascript достаточно сильно различаются. Плюс, в C для указанного выше примера будет также действовать правило sequence points, которое в данной таблице на рассмотрено.
НЛО прилетело и опубликовало эту надпись здесь
А как точки следования можно ПРИМЕНИТЬ? O_O
Я не гуру, но насколько я помню, точки следования влияют на то, что происходит МЕЖДУ ними. В данном случае конструкция как раз расположена между точками следования, соответственно внутри нее нельзя более одного раза менять значение 'a' операторами '++'/'--'.

Но это для C++, а у топикстартера Javascript. Как там с точками следования я не знаю, поверхностное гугление вскрывает только подобные вопросы 'фигли оно разное в сях и джаваскрипте' :(
Насколько я знаю, в жабаскрипте понятия «точка следования» не существует, порядок исполнения кода жестко детерминирован и не может изменяться, соответственно алгоритм исполнения данной конструкции в javascript однозначен (хоть и не совсем очевиден).
НЛО прилетело и опубликовало эту надпись здесь
Данная таблица тут не применима. Обратите внимание, постфиксный инкремент по приоритету стоит ниже присваивания, а в рассматриваемом примере он выполняется первым.
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
Только я не понимаю смысл всех этих задач на приоритеты операций?
В целом-то задача тривиальная всегда: аккуратно разложить и посмотреть что будет — думать особо не надо.

Итак, вопрос: чего мы пытаемся добиться этими задачами?
НЛО прилетело и опубликовало эту надпись здесь
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории