Студопедия

Главная страница Случайная страница

Разделы сайта

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника






Арифметические операции






В языке C# имеются обычные для всех языков арифметические операции - " +, -, *, /, %". Все они перегружены. Под перегрузкой операции понимается существование нескольких реализаций одной и той же операции. Например, операция со знаком " +" выполняется по-разному в зависимости от того, являются ли ее операнды целыми числами, длинными целыми, целыми с фиксированной или плавающей точкой или строками текста.

Операции " +" и " -" могут быть унарными и бинарными. Унарные операции приписывания знака арифметическому выражению имеют наивысший приоритет среди арифметических операций. К следующему приоритету относятся арифметические операции типа умножения, к которому относятся три операции - умножения, деления и взятия остатка. Все эти операции перегружены и определены для разных подтипов арифметического типа. Следует, однако, помнить, что арифметические операции не определены над короткими числами (byte, short) и начинаются с типа int.

Операция деления " /" над целыми типами осуществляет деление нацело, для типов с плавающей и фиксированной точкой - обычное деление. Операция " %" возвращает остаток от деления нацело и определена не только над целыми типами, но и над типами с плавающей точкой. Тип результата зависит от типов операндов.

Для целых типов можно исходить из того, что равенство x = (x/y)*y истинно. Для типов с плавающей точкой выполнение точного равенства x = (x/y)*y следует считать скорее случайным, а не закономерным событием. Законно невыполнение этого равенства, как это происходит при вычислениях с фиксированной точкой.

Ресурсы для выражений

Говоря о ресурсах, требуемых программе P, часто используют термины " временная" и " емкостная сложность" - T(P) и V(P). Выражения представляют хорошую начальную базу для оценивания этих характеристик.

Характеристики T(P) и V(P) обычно взаимосвязаны. Увеличивая расходы памяти, можно уменьшить время решения задачи или, выбирая другое решение, сократить расходы памяти, увеличивая время работы. Одна из реальных задач, стоящих перед профессиональным программистом - это нахождение нужного компромисса между памятью и временем.

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

 

Операции отношения стоит просто перечислить, в объяснениях они не нуждаются. Всего операций 6 (==,! =, <, >, < =, > =), все они возвращают результат логического типа bool. Операции перегружены, так что их операнды могут быть разных типов.

Логические операции над булевскими операндами

Операций, которые выполняются только над операндами булевского типа, три (!, & &, ||). Высший приоритет среди этих операций имеет унарная операция отрицания! x, которая возвращает в качестве результата значение, противоположное значению выраженияx. Поскольку неявных преобразований типа к типу bool не существует, то выражение x задается либо переменной булевского типа, либо, как чаще бывает, выражением отношения. Возможна ситуация, когда некоторое выражение явным образом преобразуется к булевскому типу.

Следующая по приоритету бинарная операция (x & & y) называется конъюнкцией, операцией " И" или логическим умножением. Она возвращает значение true в том и только в том случае, когда оба операнда имеют значение true. В остальных случаях возвращается значение false.

Следующая по приоритету бинарная операция (x || y) называется дизъюнкцией, операцией " ИЛИ" или логическим сложением. Она возвращает значение false в том и только в том случае, когда оба операнда имеют значение false. В остальных случаях возвращается значение true.

Когда описывается семантика операций, молчаливо предполагается, что операнды операции определены. Подразумевается, что результат операции не определен, если не определен хотя бы один из ее операндов. Это утверждение верно почти для всех операций языка C#. К исключениям относятся рассматриваемые нами логические операции & & и ||. Эти операции называются условными логическими операциями. Если первый операнд операции конъюнкции & & ложен, то второй операнд не вычисляется и результат операции равен false, даже если второй операнд не определен. Аналогично, если первый операнд операции дизъюнкции || истинен, то при выполнении этого условия второй операнд не вычисляется и результат операции равен true, даже если второй операнд не определен.

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

//Условное And - & & public int SearchPattern(int[] arr, int pattern){ int result = -1, index = 0; int n = arr.Length; while (index < n & & arr[index]! = pattern) index++; if (index! = n) result = index; return (result); }

Обратите внимание на выражение, задающее условие цикла while. Здесь условная конъюнкция выполняется над двумя отношениями. В том случае, когда образца нет в массиве, наступает момент, когда первый операнд становится ложным, в этот же момент второй операнд не определен, поскольку индекс проверяемого элемента массива выходит за допустимые пределы. Классическая конъюнкция должна в этот момент приводить к ошибке, возникновению исключительной ситуации. Но условная конъюнкция прекрасно справляется, и программа корректно работает во всех случаях.

Логические операции над булевскими операндами и целыми числами

Рассмотрим логические операции, которые могут выполняться не только над булевскими значениями, но и над целыми числами. Высший приоритет среди этих операций имеет унарная операция отрицания (~x). Заметьте: есть две операции отрицания, одна из них (! x) определена только над операндами булевского типа, другая (~x) - только над целочисленными операндами.

Говоря о логических операциях над целыми числами, следует понимать, что целые числа можно рассматривать как последовательность битов (разрядов). Каждый бит, имеющий значение 0 или 1, можно интерпретировать как логическое значение обычным образом: 0 соответствует false, 1 - true. Логическая операция, применяемая к операндам одного и того же целочисленного типа, выполняется над соответствующими парами битов, создавая результат в виде последовательности битов и интерпретируемый как целое число. По этой причине такие логические операции называются побитовыми или поразрядными операциями.

Бинарных побитовых логических операций три - &, ^, |. В порядке следования приоритетов это конъюнкция (операция " И"), исключающее ИЛИ, дизъюнкция (операция " ИЛИ"). Они определены как над целыми типами выше int, так и над булевыми типами. В первом случае они используются как побитовые операции, во втором - как обычные логические операции. Когда эти операции выполняются над булевскими операндами, то оба операнда вычисляются в любом случае, и если хотя бы один из операндов не определен, то и результат операции будет не определен. Когда необходима такая семантика логических операций, тогда без этих операций не обойтись.

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






© 2023 :: MyLektsii.ru :: Мои Лекции
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав.
Копирование текстов разрешено только с указанием индексируемой ссылки на источник.