- Арифметические операторы C#
- Арифметические операторы C#
- Унарные арифметические операторы C#
- Операторы приращения (++) и уменьшения (—)
- Унарные операторы плюса и минуса
- Бинарные арифметические операторы
- Умножение (*)
- Деление (/)
- Остаток от деления (%)
- Операторы сложения (+) и вычитания (-)
- Операторы составного присваивания
- Приоритет и ассоциативность операторов
- Итого
- Арифметические выражения си шарп
- Ассоциативность операторов
Арифметические операторы C#
уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.
При изучении любого языка программирования, будь то Delphi, Python или C#, одной из основных тем изучения на начальном этапе является перечень основных операторов в языке и их применение. Конечно, со временем работать с теми или иными операторами начинаешь, как говориться, «на автомате», но в самом начале пути изучения нового языка эта тема является безусловно одной из основных. Все возможные операторы я, конечно, сейчас рассматривать не буду, но основные всё же стоит рассмотреть, чтобы в дальнейшем не путаться в их применении.
Арифметические операторы C#
Как и в Delphi операторы делятся на две группы: унарные и бинарные.
К унарным арифметическим операторам в C# относят:
Большинство из этих операторов нам может быть известно из Delphi (кто не знает, как работает умножение или деление в Delphi?), но некоторые из операторов имеют свои особенности в C#. Например, в статье про работу с числами в C# упоминалось что деление 1/3 в C# не вернет нам результат 0,3333 Начнем с унарных.
Унарные арифметические операторы C#
Операторы приращения (++) и уменьшения (—)
Ближайшими аналогами в Delphi для этих операторов являются процедуры Inc() и Dec() .
Оператор инкремента ++ увеличивает операнд на 1, а оператор декремента — , соответственно, уменьшает операнд на 1. При этом операндом должна быть переменная, свойство или индексатор.
Например, результатом выполнения вот такого кода:
double f = 4.45; int i = 10; f++;//увеличиваем f на 1 i--;//уменьшаем i на 1 Console.WriteLine("f = , i = ",f,i);
Вроде бы все вполне себе логично — одну переменную увеличили на 1, вторую — уменьшили на 1 и вывели результат в виде строки.
«Усложним» пример и напишем следующее:
double f = 4.45; int i = 10; double a = f++; int b = i--; Console.WriteLine("a = , b = ", a, b);
Казалось бы, результат измениться не должен и строка должна быть той же, но нет. В результате мы получим:
То есть, переменные а и b получили первоначальные значения f и i . Почему так происходит?
Дело в том, что операторы инкремента и декремента в C# поддерживается в двух формах: постфиксной (например, x++ ) и префиксной (например, ++x ).
Результатом постфиксного оператора приращения или уменьшения является значение переменной перед выполнением операции, а результатом префиксного оператора, соответственно, значение переменно после выполнения операции.
Теперь, если взглянуть на пример выше, становится понятно поведение программы — мы использовали постфиксные операторы и в результате, вначале переменной a присваивается значение f , а уже потом значение переменной f увеличивается на 1. Аналогично происходит и с переменной b — она получает первоначальное значение i и только после этого i уменьшается на 1.
На первый взгляд может показаться странным, но вот такое действие:
не поменяет значение переменной i — она также останется равной нулю. Причина такого поведения C# описана выше — использовалась постфиксная форма инкремента.
Чтобы наше переменные получили измененные значения код надо переписать с использованием префиксной формы операторов, то есть вот так:
double f = 4.45; int i = 10; double a = ++f; //сначала наращиваем f на 1, а потом - присваиваем значение переменной a int b = --i; Console.WriteLine("a = , b = ",a,b);
Результатом выполнения будет строка:
Унарные операторы плюса и минуса
Как и в Delphi, унарный оператор + возвращает значение полученного операнда. Унарный оператор — изменяет знак операнда на противоположный. Здесь никаких «подводных камней» нет и результат выполнения следующего кода можно угадать с первого раза:
double f = -4.45; int i = 10; Console.WriteLine("+f = , -i = ", +f, -i);
Остается только отметить, что целочисленный тип ulong не поддерживает унарный минус. Если мы попытаемся сделать вот так:
ulong i = 10; Console.WriteLine("-i = ", -i);
То ещё до компиляции получим ошибку:
При этом для целочисленных типов ushort и uint оператор «-» работает. Вот такой код:
ushort i = 10; //создали переменную Console.WriteLine(i.GetType()); //получили тип данных для i ushort b = i; //присвоили значение i переменной b Console.WriteLine((-b).GetType()); //получили тип данных для отрицательного значения b
Выведет на экран следующее:
Бинарные арифметические операторы
Умножение (*)
Оператор умножения * вычисляет произведение операндов, например:
ushort a = 10; //создали переменную int b = 5; //присвоили значение i переменной b Console.WriteLine(a * b);
вернет значение 50 , а типом данных для произведения будет, ожидаемо, int . Соответственно, в этом примере:
float a = 10.0f; //создали переменную int b = 5; //присвоили значение i переменной b Console.WriteLine((a * b).GetType()); Console.ReadLine();
Программа вернет нам вещественный тип float (System.Single). Другое дело — оператор деления.
Деление (/)
В C# различают деление целых чисел и деление чисел с плавающей точкой (запятой).
Для операндов целочисленных типов ( int , short , uint и т.д.) результат оператора / является целочисленным типом, который равен частному двух операндов, округленному в сторону нуля. Собственно об этом мы говорили в заметке про работу с числами в C#.
Для типов float , double и decimal результатом оператора / является частное двух операндов. Однако и здесь есть момент, который стоит помнить, а именно: если один из операндов — это decimal , второй операнд не может быть ни float , ни double , так как ни float , ни double не преобразуется неявно в тип decimal . Необходимо явным образом преобразовать операнд float или double в тип decimal (также, про такое поведение C# см. здесь). Вот такой код:
decimal a = 10; double b = 3; Console.WriteLine(a / b);
Чтобы код сработал без ошибок надо произвести приведение типов, а именно переписать код следующим образом:
decimal a = 10; double b = 3; Console.WriteLine(a / (decimal)b);
и деление пройдет успешно с результатом
Остаток от деления (%)
Ближайшим «родственником» в Delphi является оператор mod . Но и здесь у C# есть свои особенности.
Для целочисленных операндов результатом a % b является значение полученное из выражения a — (a / b) * b . Знак ненулевого остатка такой же, как и у левого операнда, например:
int a = 10; int b = 3; Console.WriteLine(a % b);
вернет нам значение 1. Тут всё ровно так же, как и в Delphi. В отличие от Delphi, в C# можно получить остаток от деления вещественных чисел, например:
double a = 10.4; double b = 3.45; Console.WriteLine(a % b);
В Delphi с оператором mod такое проделать нельзя. Для получения аналогичного результата нам бы пришлось воспользоваться функцией FMod() из модуля Math .
Операторы сложения (+) и вычитания (-)
Эти операторы так же, как и везде производят математическое сложение/вычитание правого операнда из левого. Никаких подводных камней и особенностей в этом плане в C# нет.
int a = 10; double b = 3.45; Console.WriteLine(a - b);
Операторы составного присваивания
В C# имеются также операторы составного присваивания (чего нет в Delphi), которые можно использовать, например, для более короткой записи арифметических операций и в общем случае выглядят следующим образом:
где op — какой-либо из рассмотренных выше операторов. Читается такое выражение в развернутом виде следующим образом:
int a = 10; a += 10; //a=a+10 = 20; Console.WriteLine(a); a /= 10; //a = a/10 = 2; Console.WriteLine(a); a *= 5; //a = a*5 = 10 Console.WriteLine(a); a %= 3; //a = a mod 3 = 1 Console.WriteLine(a);
вернет нам значения, которые написаны в комментариях к коду, то есть строки:
При этом, в случае работы с операторами составного присваивания следует иметь в виду следующее примечание из справки Microsoft по языку C#:
Из-за восходящих приведений результат операции op может быть невозможно неявно преобразовать в тип T из x. В этом случае, если op является предопределенным оператором, и результат операции является явно преобразуемым в тип T«x, выражение составного присваивания формы x op= y эквивалентно x = (T)(x op y), за исключением того, что x вычисляется только один раз.
Пример такого поведения представлен там же в справке:
byte a = 200; byte b = 100; var c = a + b; Console.WriteLine(c.GetType()); // output: System.Int32 Console.WriteLine(c); // output: 300 a += b; Console.WriteLine(a); // output: 44
Мы бы, возможно, ожидали, что последний вывод в консоль содержал бы число 300 , но тип byte у нас только от 0 до 255. В результате в вывод попало значение ( 300-256 = 44 ).
Приоритет и ассоциативность операторов
Арифметические операторы выполняются в следующем порядке (по убыванию приоритета):
- Постфиксный инкремент x++ и декремент x—
- Префиксный инкремент ++x и декремент —x , унарные операторы + и —
- Мультипликативные операторы * , / , и %
- Аддитивные операторы + и —
Бинарные арифметические операторы имеют левую ассоциативность. То есть операторы с одинаковым приоритетом вычисляются в направлении слева направо.
Порядок вычисления, определяемый приоритетом и ассоциативностью операторов, можно изменить с помощью скобок ( () ).
Итого
Сегодня мы узнали, какие виды арифметических операторов есть в C#, как они работают и в чем их особенности. А также разобрали несколько примеров, показывающих особенности вычисления арифметических выражений в C#.
уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.
Арифметические выражения си шарп
В C# используется большинство операций, которые применяются и в других языках программирования. Операции представляют определенные действия над операндами — участниками операции. В качестве операнда может выступать переменной или какое-либо значение (например, число). Операции бывают унарными (выполняются над одним операндом), бинарными — над двумя операндами и тернарными — выполняются над тремя операндами. Рассмотрим все виды операций.
Бинарные арифметические операции:
- + Операция сложения двух чисел:
int x = 10; int z = x + 12; // 22
int x = 10; int z = x * 5; // 50
int x = 10; int z = x / 5; // 2 double a = 10; double b = 3; double c = a / b; // 3.33333333
При делении стоит учитывать, что если оба операнда представляют целые числа, то результат также будет округляться до целого числа:
double z = 10 / 4; //результат равен 2
Несмотря на то, что результат операции в итоге помещается в переменную типа double, которая позволяет сохранить дробную часть, но в самой операции участвуют два литерала, которые по умолчанию рассматриваются как объекты int, то есть целые числа, и результат то же будет целочисленный. Для выхода из этой ситуации необходимо определять литералы или переменные, участвующие в операции, именно как типы double или float:
double z = 10.0 / 4.0; //результат равен 2.5
double x = 10.0; double z = x % 4.0; //результат равен 2
Также есть ряд унарных операций, в которых принимает участие один операнд:
- ++ Операция инкремента Инкремент бывает префиксным: ++x — сначала значение переменной x увеличивается на 1, а потом ее значение возвращается в качестве результата операции.
И также существует постфиксный инкремент: x++ — сначала значение переменной x возвращается в качестве результата операции, а затем к нему прибавляется 1.
int x1 = 5; int z1 = ++x1; // z1=6; x1=6 Console.WriteLine($" - "); int x2 = 5; int z2 = x2++; // z2=5; x2=6 Console.WriteLine($" - ");
int x1 = 5; int z1 = --x1; // z1=4; x1=4 Console.WriteLine($" - "); int x2 = 5; int z2 = x2--; // z2=5; x2=4 Console.WriteLine($" - ");
При выполнении сразу нескольких арифметических операций следует учитывать порядок их выполнения. Приоритет операций от наивысшего к низшему:
Для изменения порядка следования операций применяются скобки.
Рассмотрим набор операций:
int a = 3; int b = 5; int c = 40; int d = c---b*a; // a=3 b=5 c=39 d=25 Console.WriteLine($"a= b= c= d=");
Здесь мы имеем дело с тремя операциями: декремент, вычитание и умножение. Сначала выполняется декремент переменной c, затем умножение b*a, и в конце вычитание. То есть фактически набор операций выглядел так:
Но с помощью скобок мы могли бы изменить порядок операций, например, следующим образом:
int a = 3; int b = 5; int c = 40; int d = (c-(--b))*a; // a=3 b=4 c=40 d=108 Console.WriteLine($"a= b= c= d=");
Ассоциативность операторов
Как выше было отмечено, операции умножения и деления имеют один и тот же приоритет, но какой тогда результат будет в выражении:
Стоит нам трактовать это выражение как (10 / 5) * 2 или как 10 / (5 * 2) ? Ведь в зависимости от трактовки мы получим разные результаты.
Когда операции имеют один и тот же приоритет, порядок вычисления определяется ассоциативностью операторов. В зависимости от ассоциативности есть два типа операторов:
- Левоассоциативные операторы, которые выполняются слева направо
- Правоассоциативные операторы, которые выполняются справа налево
Все арифметические операторы являются левоассоциативными, то есть выполняются слева направо. Поэтому выражение 10 / 5 * 2 необходимо трактовать как (10 / 5) * 2 , то есть результатом будет 4.