Арифметические выражения си шарп

Арифметические операторы C#

уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.

При изучении любого языка программирования, будь то Delphi, Python или C#, одной из основных тем изучения на начальном этапе является перечень основных операторов в языке и их применение. Конечно, со временем работать с теми или иными операторами начинаешь, как говориться, «на автомате», но в самом начале пути изучения нового языка эта тема является безусловно одной из основных. Все возможные операторы я, конечно, сейчас рассматривать не буду, но основные всё же стоит рассмотреть, чтобы в дальнейшем не путаться в их применении.

Арифметические операторы C#

Как и в Delphi операторы делятся на две группы: унарные и бинарные.

К унарным арифметическим операторам в C# относят:

Большинство из этих операторов нам может быть известно из Delphi (кто не знает, как работает умножение или деление в Delphi?), но некоторые из операторов имеют свои особенности в C#. Например, в статье про работу с числами в C# упоминалось что деление 1/3 в C# не вернет нам результат 0,3333 Начнем с унарных.

Унарные арифметические операторы C#

Операторы приращения (++) и уменьшения (—)

Ближайшими аналогами в Delphi для этих операторов являются процедуры Inc() и Dec() .

Оператор инкремента ++ увеличивает операнд на 1, а оператор декремента — , соответственно, уменьшает операнд на 1. При этом операндом должна быть переменная, свойство или индексатор.

Читайте также:  Php failed to write cache file

Например, результатом выполнения вот такого кода:

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.

Источник

Оцените статью