Приоритет операторов и порядок вычислений

Когда компьютер встречает уравнение, он выполняет математические действия не просто слева направо. Прежде всего он просматривает строку и определяет порядок выполнения операций, основываясь на приоритете операторов. Приоритет операторов означает, что одни операторы выполняются раньше других независимо от того, в какой последовтельности они записаны в уравнении. Приоритет операторов умножения и деления выше, чем приоритет сложения и вычитания, что совпадает с последовательностью выполнения математических действий в уравнении (вспомните школьные примеры на «порядок действий»).

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

Рассмотрим простое уравнение:

a = 1 + 4 / 2 * 5 + 3;

Если выполнять действия просто слева направо, не отдавая предпочтения ни одному из них, полученный результат будет равен 15.5 (рис.6.5). Однако компьютер учитывает порядок выполнения математических операций, и результат поэтому получится равным 14 (на рис.6.6 показано, как вычисляется этот результат). Когда вы пишете программу, следует внимательно следить за тем, выполняются ли математические операции в желаемом порядке.

Приоритет операторов и порядок вычислений - student2.ru
Рис. 6.5. Выполнение математических операций без учета приоритета

Приоритет операторов и порядок вычислений - student2.ru
Рис. 6.6. Компьютер выполняет математические операциис учетом приоритета операторов

____________________________________

* Автор имел в виду машинный стек, но на самом деле современные компиляторы чаще сохраняют промежуточные результаты вычислений на регистрах центрального процессора, а значения выражений, не содержащих имен переменных, вычисляют еще на стадии компиляции. (Прим.перев.)

Очень часто начинающие программисты допускают ошибку при расчетах средних значений. В Листинге 6.3 приведен текст программы, в которой сделана попытка ввести три числа и вычислить их среднее арифметическое. Мы говорим «попытка», так как полученное в результате работы этой программы значение будет неправильным. Проверьте, сможете ли вы определить, почему?

Листинг 6.3. Неправильная программа расчета среднего арифметического значения трех чисел.

/*average.c*/main() { float number_1, number_2, number_3, average; printf("Введите первое число: "); scanf("%f", &number_1); printf("Введите второе число: "); scanf("%f", &number_2); printf("Введите третье число: "); scanf("%f", &number_3); average = number_1 + number_2 + number_3 / 3; printf("Среднее арифметическое равно %f", average); }

Ошибка содержится в инструкции

average = number_1 + number_2 + number_3 / 3;

Дойдя до этой строки программы, компьютер будет выполнять математические действия в следующем порядке:

  1. Поделит значение переменной number_3 на 3.
  2. Сложит значения переменных number_1 и number_2 и прибавит к ним результат деления.

Если вы присвоите каждой переменной значение 100, выведенное на экран среднее арифметическое будет равняться 233.33. Вот правильная запись этой строки инструкций:

average = (number_1 + number_2 + number_3) / 3;

Круглые скобки изменяют порядок приоритетов. Просматривая эту строку, компьютер прежде всего выполнит действия в скобках, затем вернется к началу строки и выполнит остальные операции в соответствии с обычным приоритетом операторов, о котором мы только что говорили. Таким образом, в нашей программе будет сперва выполнено сложение трех чисел в скобках, а потом результат поделен на 3 (рис.6.7). Вуаля! Получился правильный ответ.

Приоритет операторов и порядок вычислений - student2.ru
Рис. 6.7. Правильная формула расчета среднего арифметического значения

Приоритет операторов и порядок вычислений - student2.ru
Рис. 6.8. Использование нескольких уровней круглых скобок

Для того чтобы установить нужный порядок выполнения операций, можно использовать несколько уровней скобок (рис.6.8). Порядок выполнения операций установлен от самых внутренних скобок к наружным.

Рассмотрим пример. Допустим, работник получает оплату в двойном размере за каждый час, проработанный сверх 40-часовой рабочей недели. Полагая, что он работает как минимум 40 часов и, соответственно, получает плату как минимум за 40 рабочих часов, расчет недельного заработка состоит из следующих частей:



40 * rate /* обычный недельный заработок */hours – 40 /* сверхурочные часы */rate * 2 /* оплата сверхурочных */

где rate — плата за 1 час работы, а hours — общее количество проработанных часов. В этом уравнении надо умножить количество сверхурочных часов на оплату в двойном размере, а затем прибавить полученный результат к обычной недельной оплате. Если вы напишете уравнение без учета приоритета операторов, оно будет выглядеть так:

total = 40 * rate + hours - 40 * rate * 2

Допустим теперь, некто проработал 48 часов в неделю, причем его обычный заработок составляет 10 долларов в час. В приведенном уравнении операции будут выполняться в следующем порядке:

Операция Результат
40 * rate
40 * rate
400 * 2
400 + 48
448 – 800 –352

Согласитесь, что получить недельный заработок в размере –352 доллара несколько обидно. Чтобы написать правильное уравнение, используйте скобки: total = (40 * rate) +((hours - 40) * (rate * 2)) Теперь уравнение состоит из двух логических частей (полный текст программы приведен в Листинге6.4). В первых скобках вычисляется обычная заработная плата, во вторых — оплата сверхурочных. Расчет сверхурочных тоже состоит из двух частей, заключенных в собственные скобки. Си прежде всего выполнит операции во внутренних скобках. Порядок выполнения действий теперь станет таким:

Операция Результат
40 * rate
hours – 40
rate * 2
8 * 20
400 + 160

Листинг 6.4. Программа расчета недельного заработка с учетом сверхурочных.

/*payroll1.c*/main() { float rate, hours, total; printf("Введите оплату одного часа работы: "); scanf("%f", &rate); printf("Введите количество отработанных часов: "); scanf("%f", &hours); total = (40 * rate) + ((hours -40) * (rate*2)); printf("Ваш недельный заработок: %f", total); }

Если вы находите, что использование скобок сбивает вас с толку, разбейте уравнение на несколько отдельных частей. В Листинге6.5 приведен текст программы, которая выполняет тот же расчет недельного заработка, но проводит его в несколько последовательных этапов, определяя для этого дополнительные переменные. Результат каждого отдельного вычисления присваивается конкретной переменной и может быть выведен на экран, что делает получаемую информацию даже несколько более наглядной. Этот прием позволяет полностью контролировать весь процесс вычисления и с большей легкостью находить ошибки.

Листинг 6.5. Программа, осуществляющая вычисление в несколько этапов.

/*payroll2.c*/main(){float rate, hours, total, regular, extra, d_time, overtime;printf("Введите оплату одного часа работы: ");scanf("%f", &rate);printf("Введите количество отработанных часов: ");scanf("%f", &hours);regular = 40 * rate;extra = hours - 40;d_time = rate * 2;overtime = extra * d_time;total = regular + overtime;printf("Ваш недельный заработок: %f", total);}

Наши рекомендации