Как определяется порядок вычислений в сложном условии? Как его изменить?
Пожалуйста, войдите или зарегистрируйтесь для публикации ответа на этот вопрос.
решение вопроса
Связанных вопросов не найдено
Обучайтесь и развивайтесь всесторонне вместе с нами, делитесь знаниями и накопленным опытом, расширяйте границы знаний и ваших умений.
поделиться знаниями или
запомнить страничку
- Все категории
- экономические 43,679
- гуманитарные 33,657
- юридические 17,917
- школьный раздел 612,508
- разное 16,911
Популярное на сайте:
Как быстро выучить стихотворение наизусть? Запоминание стихов является стандартным заданием во многих школах.
Как научится читать по диагонали? Скорость чтения зависит от скорости восприятия каждого отдельного слова в тексте.
Как быстро и эффективно исправить почерк? Люди часто предполагают, что каллиграфия и почерк являются синонимами, но это не так.
Как научится говорить грамотно и правильно? Общение на хорошем, уверенном и естественном русском языке является достижимой целью.
- Обратная связь
- Правила сайта
2.9 Порядок вычисления выражений

Порядок выполнения операций, входящих в выражения, определяется приоритетом операций. Для изменения порядка вычисления используются круглые скобки. Приоритет операций:
- вычисления в круглых скобках ( )
- вычисления значений функций
- унарные операции not
- операции типа умножение *, /, div, mod, and
- операции типа сложение +, -, or, xor
- операции сравнения >, =, =, <>
Следует учесть, что в отличие от многих других языков программирования в Турбо Паскале логические операции имеют более высокий приоритет, чем операции отношения. В связи с этим, в сложных логических выражениях обычно необходимо расставлять скобки. Если, например, b и с имеют тип INTEGER , то выражение а = b and с < d вызовет сообщение о синтаксической ошибке, так как сначала выполнится операция b and с. Правильным будет выражение: (а = b) and (с < d) Задачи для самоконтроля2.1 Вычислить значения выражений а) 20 div 6; б) 20 mod 6; в) 2 div 5; г) 2 mod 5; д) 4 div 0; е) 2.0 mod 2. 2.2. а) Преобразовать арифметическое выражение в линейную форму записи, пригодную для ввода в компьютер. Использовать следующие обозначения операций: умножение *, деление /, возведение в степень ^, т.е. x 3 = x^3. б) Преобразовать линейную форму записи арифметического выражения в «многоэтажное» представление, обычно используемое в математике: B:=(x/(y+3*(x–y))^2–(y+9)^3/4)/(x^2*y)+9.5*y^2+y*(8+x/(2*y)). 2.3 Какие операторы являются ошибочными? var x:integer; y:real; Begin x:=3.4; y:=5; x:=6; y:=2.5; x:=y; y:=x; x:= 6/3; x:= 6 div 3; y:= 6 div 2; 2.4 Вычислить значения выражений а) not (6>=4) and (2<8) б) ((5>=9) or (4>2)) and (6<12)
3. Операторы языка Паскаль
Описывают некоторые действия, которые необходимо выполнить для решения задачи. Тело программы представляет собой последовательность операторов (команд), которые разделяются «;». Напомним порядок выполнения операторов программы: слева направо сверху вниз.
3.1 Оператор присваивания
Обозначается := . Вызывает вычисление выражения стоящего справа от него, и присваивание вычисленного значения переменной, стоящей слева. Таким образом, с помощью этого оператора в ячейку памяти, имя которой указано слева от знака := , заносится значение, находящееся справа от знака := .
| Фрагмент программы: y:=7; x:=y; a:=3; b:=25 z:=a+b; i:=4; j:=8; res:=(i>0) and (i<100); k:=sqr(a)+i*j; | Содержимое ячеек памяти (имя указано слева) после выполнения соответствующей команды присвоения: 7 y 7 x a 3 25 b z 28 4 8 i j r True es 41 k |
3.2 Составной оператор
Представляет собой совокупность последовательно выполняемых операторов, заключенных в операторные скобки begin … end. Структура оператора следующая: begin оператор 1>; оператор 2>; … оператор 3>; end; Используется, когда необходимо выполнить несколько действий, а синтаксисом языка допускается только один оператор. Само тело программы тоже можно считать составным оператором.
[sicp] Порядок вычислений.
Я не могу понять разницу между аппликативным и нормальным порядком вычисления. Просветите меня на тему их различий.
milton
28.01.10 16:55:55 MSK
При аппликативном порядке аргументы функции вычисляются перед тем, как отправить их внутрь функции.
При нормальном порядке аргументы отправляются внутрь функции эээ. целиком. Скажем, в f(1+2,3) выражение 1+2 будет «целиком» передано вовнутрь.
В книжке Филда и Харрисона «Функциональное программирование» более понятно и подробно объяснено
anonymous
( 28.01.10 17:02:10 MSK )
Ответ на: комментарий от anonymous 28.01.10 17:02:10 MSK
Аналогия с лямбда-исчислением вроде такая:
аппликативный порядок — бета-контракция по самим внутренним редексам
нормальный порядок — бета-контракция по самим внешним редексам
anonymous
( 28.01.10 17:06:35 MSK )
Ответ на: комментарий от anonymous 28.01.10 17:06:35 MSK
anonymous
( 28.01.10 17:07:48 MSK )

при нормальном порядке аргументы при аппликации функции не вычисляются, вычисляется сначала функция, ну, т.е. грубо говоря, «самый наружный терм».
при аппликативном порядке вычисления, как следует из названия, вычисление аргументов происходит при аппликации функции, т.е. вычисляются сначала все аргументы, а потом функция применяется к ним, т.е. сначала вычисляются все «внутренние термы».
В Common Lisp разница довольно ясно видна, там у функций — аппликативный порядок вычисления, а у макросов — нормальный.
Love5an
( 28.01.10 17:09:16 MSK )
Ответ на: комментарий от anonymous 28.01.10 17:06:35 MSK
Да, действительно, думаю так ТС лучше поймёт.
Dikar ★★
( 28.01.10 17:45:10 MSK )

на примера мат. ф-ции: f(x) = x + x
Аппликативный п.в.: f(1 + 2) -> f(3) -> 3+3 -> 6
Нормальный п.в.: f(1 + 2) -> (1+2) + (1+2) -> 3 + (1+2) -> 3+3 -> 6
если также построить f(x) = x+x+x будет лучше видно, какое из этих вычислений затратит меньше шагов и на сколько
pseudo-cat ★★★
( 28.01.10 19:16:50 MSK )
Ответ на: комментарий от pseudo-cat 28.01.10 19:16:50 MSK

если также построить f(x) = x+x+x будет лучше видно, какое из этих вычислений затратит меньше шагов и на сколько
только давайте честно, а? во втором случае будет нормальная редукция графов, а не то что на примере
jtootf ★★★★★
( 28.01.10 19:52:22 MSK )
Ответ на: комментарий от pseudo-cat 28.01.10 19:16:50 MSK
*поперхнулся кофе* Ну нельзя же ТАК передёргивать?
kemm ★
( 28.01.10 19:56:00 MSK )
Ответ на: комментарий от jtootf 28.01.10 19:52:22 MSK

хз, это усложнение и, наверное, далеко не единственное в реальном алгоритме, а то что в примере главная суть алгоритма. или нет?
pseudo-cat ★★★
( 28.01.10 20:06:19 MSK )
Ответ на: комментарий от pseudo-cat 28.01.10 20:06:19 MSK

на этом стоило остановиться. если не разбираешься — зачем пишешь?
jtootf ★★★★★
( 28.01.10 20:25:37 MSK )
Ответ на: комментарий от Love5an 28.01.10 17:09:16 MSK
>В Common Lisp разница довольно ясно видна, там у функций — аппликативный порядок вычисления, а у макросов — нормальный.
anonymous
( 28.01.10 20:40:04 MSK )
>Я не могу понять разницу между аппликативным и нормальным порядком вычисления.
в отличии от аппликативного, нормальный порядок всегда приводит терм к нормальной форме, если это возможно. вот классический пример:
(λx. y) ((λx. x x x) (λx. x x x))
anonymous
( 28.01.10 20:44:50 MSK )
Ответ на: комментарий от jtootf 28.01.10 20:25:37 MSK

на этом стоило остановиться. если не разбираешься — зачем пишешь?
чтобы узнать как правильно
а в чём суть то?
pseudo-cat ★★★
( 29.01.10 00:26:55 MSK )
Ответ на: комментарий от pseudo-cat 29.01.10 00:26:55 MSK

во-первых, как уже отметили выше, нормальный порядок редукции всегда приведёт к нормальной форме (в отличие от аппликативного); во-вторых, редукция графов никогда не требует больше шагов вычислений, чем аппликативный порядок. а, собственно, реализация ленивых вычислений всегда предполагает outermost graph reduction
лучше видно, какое из этих вычислений затратит меньше шагов и на сколько
чуть более чем наполовину некорректно. сложность по памяти — да, тут оверхед на санки может существенно ухудшить картину; но по количеству шагов вычислений ситуация с точностью до наоборот
jtootf ★★★★★
( 29.01.10 01:28:56 MSK )
Ответ на: комментарий от jtootf 29.01.10 01:28:56 MSK

ага, понятно, спасибо, вот только не очень понял что есть нормальная форма? и
pseudo-cat ★★★
( 29.01.10 02:02:18 MSK )
Ответ на: комментарий от pseudo-cat 29.01.10 02:02:18 MSK

A normal form is an equivalent expression which cannot be reduced any further
конец вычислений, иными словами
jtootf ★★★★★
( 29.01.10 02:19:35 MSK )
Ответ на: комментарий от anonymous 28.01.10 20:40:04 MSK

В каком месте?
Ты, вообще, в курсе что такое макросы и как раскрываются?
Love5an
( 29.01.10 05:40:12 MSK )
Ответ на: комментарий от Love5an 29.01.10 05:40:12 MSK
>В каком месте?
ну вот то что ты написал — оно самое. макросы вычисляют в произвольном порядке, или не вычисляют, или вычисляют несколько раз. и работают до выполнения программы, раскрываясь при интерпретации или компиляции. ты не прав.
anonymous
( 29.01.10 06:34:56 MSK )
Ответ на: комментарий от anonymous 29.01.10 06:34:56 MSK

В какое время они работают — не имеет значения, это вообще параллельно. Можно, в принципе, считать, что в macroexpansion time cl превращается в такой отдельный язык программирования, со своими правилами вычисления.
Редукция в макросах происходит от внешних термов к внутренним, это и есть главный признак нормального порядка вычислений. Насчет «не вычисляют» — так, собственно, normal order это разновидность non-strict вычислений, все так и есть, аргументы могут вообще не вычислиться.
Love5an
( 29.01.10 06:45:58 MSK )
Ответ на: комментарий от Love5an 29.01.10 06:45:58 MSK

Ну, т.е. конкретнее.
Упростим немного модель, и представим, что макрос это такая процедура без побочных эффектов, которая обрабатывает код, то есть принимает на вход код и возвращает тоже код, а функция — такая процедура, которая работает с числами.
(defmacro m-plus (a b) (list (quote +) a b)) (defun f-plus (a b) (+ a b))
Конструкцию вида
(plus (plus 1 2) (plus 3 4))
макросы и функции обрабатывают по-разному У функций редукция происходит по такой схеме(читать сверху вниз):
(f-plus (f-plus 1 2) (f-plus 3 4)) (f-plus 3 7) 10
Сначала, как видно, вычислились аргументы, т.е. внутренние термы, и только потом внешний терм применился к ним. Это называется аппликативный порядок вычисления.
С макросами дело совсем по-другому:
(m-plus (m-plus 1 2) (m-plus 3 4)) (+ (m-plus 1 2) (m-plus 3 4)) (+ (+ 1 2) (+ 3 4))
То есть, сначала компилятор раскрывает самый внешний макрос, и только потом раскрывает внутренние макросы в получившемся коде(если, конечно, самый внешний терм результата в итоге не является опять же макросом, в таком случае он раскрывает сначала его)
Love5an
( 29.01.10 07:21:04 MSK )
Ответ на: комментарий от Love5an 29.01.10 07:21:04 MSK
использование цитирования и обычной отсутствие рекурсии. это не нормальный порядок вычислений.
anonymous
( 29.01.10 08:50:43 MSK )
Ответ на: комментарий от anonymous 29.01.10 08:50:43 MSK

При чем тут цитирование, и, тем более, отсутствие рекурсии? Перечитай пост.
Love5an
( 29.01.10 09:06:02 MSK )
Ответ на: комментарий от Love5an 29.01.10 09:06:02 MSK
и как же без него и обычных функций (или форм, кстати, цитирование сюда тоже относится) будут работать макросы?
нет самих вычислений.
p.s. пример с цитированием:
(defmacro fail (a x (b y (c z1 z2))) `(,c ,z2 (,b ,z1 (,a ,x ,y)))) (macroexpand-1 '(fail m-plus 1 (m-plus 2 (m-plus 3 4)))) (M-PLUS 4 (M-PLUS 3 (M-PLUS 2 1))) (macroexpand-1 '(fail f1 1 (f2 2 (f3 3 4)))) (F3 4 (F2 3 (F1 2 1))) (defmacro fail2 (a b c d) `(,d ,c ,b ,a)) (macroexpand-1 '(fail2 1 2 3 +)) (+ 3 2 1) (defmacro fail3 (a b c d) `(,d ,a ,c ,a ,b ,a)) (macroexpand-1 '(fail3 1 2 3 +)) (+ 1 3 1 2 1) (defmacro epic-fail (a x (b y (c z1 z2))) `(,a ,z2 (,a ,z1 (,a ,y ,x))))
с его помощью легко менять порядок и число вычислений аргументов и даже раскрытия форм.
anonymous
( 29.01.10 09:46:00 MSK )
Ответ на: комментарий от anonymous 29.01.10 09:46:00 MSK

Ты совсем дурак?
Перечитай мой пост, потом перечитай где-нибудь определение «normal order of evaluation» — в SICP, в википедии или на c2.com, к примеру.
Love5an
( 29.01.10 09:50:52 MSK )
Ответ на: комментарий от Love5an 29.01.10 09:50:52 MSK
это же задумывалась для первого знакомства с программированием школьникам/первокурсникам. там многие сложные вопросы очень такчино обходят.
перечитай где-нибудь определение «normal order of evaluation»
ты бы для сначала определение evaluation осилил.
anonymous
( 29.01.10 10:52:37 MSK )
Ответ на: комментарий от anonymous 29.01.10 10:52:37 MSK

Все с тобой понятно.
Ну извини, не могу никак компенсировать твою умственную недостаточность.
Love5an
( 29.01.10 11:03:35 MSK )
Ответ на: комментарий от Love5an 29.01.10 11:03:35 MSK
где ты видел цитирование в лямбда исчислении? что будет с (defmacro x () (x))?
О порядке вычисления выражений
Как известно, оператор побитого сдвига вычисляется слева на право — но при вводе 1 2 вывод 2 1 (компилятор от майкрософта), с чем это связано ? порождает ли данный код undefined behaviour или здесь всего лишь порядок вывода неопределён ? Если убрать код чтения — всё довольно предсказуемо
int readValue(int v) < return v; >int main()
вывод — 1 2 в чем дело ?
Отслеживать
122k 24 24 золотых знака 124 124 серебряных знака 297 297 бронзовых знаков
задан 11 ноя 2016 в 21:34
3,681 1 1 золотой знак 17 17 серебряных знаков 31 31 бронзовый знак
а разве компилятор не может вставить вычисление этих функций в удобном для него порядке?
11 ноя 2016 в 21:43
@KoVadim а что имеется ввиду под «удобный для компилятора порядок» ? но не ясно с порядком
11 ноя 2016 в 21:48
а это сложная тема. Но в целом, решается создателями компилятора. К примеру, можно сделать меньше размер кода.
11 ноя 2016 в 21:57
Учтите, что данные Вам ответы релевантны для C++ версии до 17 года, с 17 года ответ будет другой.
12 ноя 2016 в 10:47
3 ответа 3
Сортировка: Сброс на вариант по умолчанию
Согласно стандарту C++ порядок вычисления аргументов функции не специфицирован, что означает, что компиляторы могут выбрать любой порядок вычисления аргументов Из стандарта C++ (1.9 Program execution)
3 Certain other aspects and operations of the abstract machine are described in this International Standard as unspecified (for example, order of evaluation of arguments to a function).
cout
operator <<( operator <<( std::cout.operator <<( readValue() ), ' ' ) .operator <<( readValue() ), '\n' );
MS VC++ вычисляет аргументы справа налево. Другой компилятор может вычислять аргументы в другом порядке, например, слева направо.
EDIT: Я приведу дополнительный наглядный пример на основе перегрузки оператора operator && .
Рассмотрите следующую демонстрационную программу
#include struct A < int x; A( int x = 0 ) : x( x ) <>>; bool operator &&( const A &a, int x ) < return 0 < a.x && 0 < x; >A f1() < std::cout int f2() < std::cout int main(void)
Ее вывод на консоль следующий
f2() f1() 0
Если бы это был встроенный оператор operator && для фундаментальных типов, то выражение f2() не вычислялось бы в случае, если выражение f1() имело значение false .
Однако так как здесь имеет место вызов перегруженной пользователем функции, то порядок выполняемых действий компилятором следующий.
Компилятор сначала пытается определить, какая именно из перегруженных функций используется. Если он такой не находит, или имеет место неоднозначность, то компилятор выдает сообщение об ошибке. Если он находит такую функцию, то он заменяет данную запись на вызов соответствующей функции пользователя. И на основе этого вызова функции строит результирующий объектный код. Так как порядок вычисления аргументов функции не специфицирован, то, как показывает вывод, компилятор сначала вычислил правый аргумент, а затем левый.
Сравните вывод данной программы с выводом программы, в которой оператор operator && имеет дело с фундаментальными типами, то есть когда используется встроенный оператор operator && .
#include int f1() < std::cout int f2() < std::cout int main(void)
Вывод программы на консоль
f1() 0
Как видно, функция f2 никогда не будет вызвана, так как значение левого операнда равно false .
Это различие связано с тем, что в первом случае компилятор имеет дело с вызовом именно пользовательской функции с именем operator && ,а во втором случае имеет дело со встроенным оператором operator && .