Операции и выражения. Правила формирования и вычисления выражений. Математические функции (класс Math).
Арифметические операции языка C#
В C# используется большинство операций, которые применяются и в других языках программирования. Операции представляют определенные действия над операндами. В качестве операнда может выступать переменная или какое-либо значение (например, число). Операции бывают унарными (выполняются над одним операндом), бинарными - над двумя операндами и тернарными - выполняются над тремя операндами.
+, -, *, /;
% -остаток от деления;
++ инкримент;
-- декремент.
int x = 10;
int z = x + 12; // 22
int z = x - 6; // 4
int z = x * 5; // 50
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
Операции инкремент и декремент - это одноместные (унарные) операции.
Операция инкремента (увеличение на 1)
Инкремент бывает префиксным: ++x - сначала значение переменной x увеличивается на 1, а потом ее значение возвращается в качестве результата операции.
Существует также постфиксный инкремент : x++ - сначала значение переменной x возвращается в качестве результата операции, а затем к нему прибавляется 1.
int x1 = 5;
int z1 = ++x1; // z1=6; x1=6
int x2 = 5;
int z2 = x2++; // z2=5; x2=6
Операция декремента (уменьшения значения на единицу).
Также существует префиксная форма декремента (--x) и постфиксная (x--).
int x1 = 5;
int z1 = --x1; // z1=4; x1=4
int x2 = 5;
int z2 = x2--; // z2=5; x2=4
При выполнении сразу нескольких арифметических операций следует учитывать порядок их выполнения (приоритет). Приоритет операций от наивысшего к низшему:
- Инкремент, декремент
- Умножение, деление, получение остатка
- Сложение, вычитание
Для изменения порядка следования операций применяются скобки.
int a = 3;
int b = 5;
int c = 40;
int d = ( c-- ) -b*a; // a=3 b=5 c=39 d=25
С помощью скобок мы могли бы изменить порядок выполнения операций.
int a = 3;
int b = 5;
int c = 40;
int d = (c-(--b))*a; // a=3 b=4 c=40 d=108
Ассоциативность операторов
Операции умножения и деления имеют один и тот же приоритет, но какой тогда результат будет в выражении:
int x = 10 / 5 * 2;
Как понимать это выражение как (10 / 5) * 2 или
как 10 / (5 * 2)?
В зависимости от трактовки мы получим разные результаты.
Когда операции имеют один и тот же приоритет, порядок вычисления определяется ассоциативностью операторов. В зависимости от ассоциативности есть два типа операторов:
- левоассоциативные операторы, которые выполняются слева направо;
- правоассоциативные операторы, которые выполняются справа налево.
Все арифметические операторы (кроме префиксного инкремента и декремента) являются левоассоциативными , то есть выполняются слева направо. Поэтому выражение 10 / 5 * 2 необходимо трактовать как (10 / 5) * 2, то есть результатом будет 4.
Поразрядные операции
Особый класс операций представляют поразрядные операции. Они выполняются над отдельными разрядами числа. Числа рассматриваются в двоичном представлении, например, 2 в двоичном представлении 10 и имеет два разряда, число 7 - 111 и имеет три разряда.
Логические операции
&(логическое умножение)
| (логическое сложение)
^ (логическое исключающее ИЛИ). Также эту операцию называют XOR .
~ (логическое отрицание или инверсия)
int x1 = 2; //010
int y1 = 5;//101
int z1 = x1&y1; //000
int x2 = 4; //100
int y2 = 5; //101
int z2 = x1&y2; //100
int Z3 = x1|y1; //111
int z4=x2|y2; //101
Для операции исключающее ИЛИ: если значения текущего разряда у обоих чисел разные, то возвращается 1, иначе возвращается 0.
int x = 45; // 101101
int key = 102; // 1100110
int encrypt = x ^ key; // 1001011
Для операции ~ (логическое отрицание или инверсия)
Если в операндах значение разряда равно 1, то оно становится равным нулю, и наоборот.
int x = 12; // 00001100
int z= ~x; // 11110011
Представление отрицательных чисел
Для записи чисел со знаком в C# применяется дополнительный код , при котором старший разряд является знаковым. Если его значение равно 0, то число положительное, и его двоичное представление не отличается от представления беззнакового числа.
Например , 0000 0001 в десятичной системе 1.
Если старший разряд равен 1, то мы имеем дело с отрицательным числом.
Например , 1111 1111 в десятичной системе представляет -1.
1111 0011 представляет -13.
Чтобы получить из положительного числа отрицательное, его нужно инвертировать и прибавить единицу:
сдвиг вправо; сдвиг влево) Операции сдвига также производятся над разрядами чисел. Сдвиг может происходить вправо и влево. x - сдвигает число x влево на y разрядов. Например, 4 xy - сдвигает число x вправо на y разрядов. Например, 161 сдвигает число 16 (которое в двоичном представлении 10000) на один разряд вправо, то есть в итоге получается 1000 или число 8 в десятичном представлении. Сдвиг влево на один разряд равноценен умножению на 2. Сдвиг вправо на один разряд равноценен делению на 2. Поэтому вместо умножения и деления можно использовать операции сдвига. " width="640"
Операции сдвига ( сдвиг вправо; сдвиг влево)
Операции сдвига также производятся над разрядами чисел. Сдвиг может происходить вправо и влево.
x - сдвигает число x влево на y разрядов. Например, 4
xy - сдвигает число x вправо на y разрядов. Например, 161 сдвигает число 16 (которое в двоичном представлении 10000) на один разряд вправо, то есть в итоге получается 1000 или число 8 в десятичном представлении.
Сдвиг влево на один разряд равноценен умножению на 2.
Сдвиг вправо на один разряд равноценен делению на 2. Поэтому вместо умножения и деления можно использовать операции сдвига.
Выражения в С #
Выражение – это последовательность операндов, знаков операций и круглых скобок.
Выражение вычисляется в соответствие с приоритетом операций слева направо.
Тип выражения зависит от типа операндов.
y = (( a+d)*t-c+(a-b)*e)-f;
Операнды в выражении могут иметь разный тип.
В этом случае при вычислении выражения происходит преобразование типов.
Преобразования базовых типов данных
Преобразования могут быть сужающие и расширяющие. Расширяющие преобразования расширяют размер объекта в памяти.
byte a = 4; // 0000100
ushort b = a; // 000000000000100
В данном случае переменной типа ushort присваивается значение типа byte. Тип byte занимает 1 байт (8 бит), и значение переменной a в двоичном виде можно представить как:100000100
Значение типа ushort занимает 2 байта (16 бит). И при присвоении переменной b значение переменной a расширяется до 2 байт: 0000000000000100.
Сужающие преобразования, наоборот, сужают значение до типа меньшей разрядности.
ushort a = 4;
byte b = (byte) a;
Здесь переменной b, которая занимает 8 бит, присваивается значение ushort, которое занимает 16 бит.
То есть из 0000000000000100 получаем 00000100. Таким образом, значение сужается с 16 бит (2 байт) до 8 бит (1 байт).
Явные и неявные преобразования
Неявные преобразования
В случае с расширяющими преобразованиями компилятор сам выполняет все преобразования данных, то есть преобразования были неявными ( implicit conversion ). Если производится преобразование от безнакового типа меньшей разрядности к безнаковому типу большой разрядности, то добавляются дополнительные биты, которые имеют значение 0. Это называется дополнение нулями .
byte a = 4; // 0000100
ushort b = a; // 000000000000100
Если производится преобразование к знаковому типу, то битовое представление дополняется нулями, если число положительное, и единицами, если число отрицательное. Последний разряд числа содержит знаковый бит - 0 для положительных и 1 для отрицательных чисел. При расширении в добавленные разряды компилируется знаковый бит.
Рассмотрим преобразование положительного числа:
sbyte a = 4; // 0000100
short b = a; // 000000000000100
Преобразование отрицательного числа:
sbyte a = -4; // 1111100
short b = a; // 111111111111100
short - int - long - decimal int - double short - float - double char - int " width="640"
Явные преобразования
При явных преобразованиях ( explicit conversion ) мы сами должны применить операцию преобразования.
Суть операции преобразования типов состоит в том, что перед значением указывается в скобках тип, к которому надо привести данное значение:
int a = 4;
int b = 6;
byte c = (byte)(a+b);
Расширяющие преобразования от типа с меньшей разрядностью к типу с большей разрядностью компилятор проводит неявно. Это могут быть следующие цепочки преобразований:
byte - short - int - long - decimal
int - double
short - float - double
char - int
Все безопасные автоматические преобразования можно описать следующей таблицей:
(больше) = (больше или равно) " width="640"
Условные выражения
Условные выражения возвращают логическое значение, то есть значение типа bool : true , если выражение истинно, и false , если выражение ложно. К подобным операциям относятся операции сравнения и логические операции.
== (равно)
!= (не равно)
(больше)
= (больше или равно)
b; // true bool d = a 25; // false Операции = имеют больший приоритет, чем == и != Логические операции В C# определены логические операторы, которые также возвращают значение типа bool. В качестве операндов они принимают значения типа bool. Как правило, применяются к отношениям и объединяют несколько операций сравнения. К ним относят: | - операция логического сложения или логическое ИЛИ. Возвращает true, если хотя бы один из операндов возвращает true. " width="640"
int a = 10;
int b = 4;
bool c = a == b; // false
bool c = a
bool c = a b; // true
bool d = a 25; // false
Операции = имеют больший приоритет, чем == и
!=
Логические операции
В C# определены логические операторы, которые также возвращают значение типа bool. В качестве операндов они принимают значения типа bool. Как правило, применяются к отношениям и объединяют несколько операций сравнения. К ним относят:
| - операция логического сложения или логическое ИЛИ. Возвращает true, если хотя бы один из операндов возвращает true.
6) | (4 6 - false, 4 bool x2 = (5 6) | (4 6); // 5 6 - false, 4 6 - false, поэтому возвращается false & - операция логического умножения или логическое И. Возвращает true, если оба операнда одновременно равны true. bool x1 = (5 6) & (4 6 - false, 4 bool x2 = (5 || - Операция логического сложения. Возвращает true, если хотя бы один из операндов возвращает true. bool x1 = (5 6) || (4 // 5 6 - false, 4 " width="640"
bool x1 = (5 6) | (4 6 - false, 4
bool x2 = (5 6) | (4 6); // 5 6 - false, 4 6 - false, поэтому возвращается false
& - операция логического умножения или логическое И. Возвращает true, если оба операнда одновременно равны true.
bool x1 = (5 6) & (4 6 - false, 4
bool x2 = (5
|| - Операция логического сложения. Возвращает true, если хотя бы один из операндов возвращает true.
bool x1 = (5 6) || (4
// 5 6 - false, 4
6) && (4 // 5 6 - false, 4 bool x2 = (5 // 5 6 - true, поэтому возвращается true ! - Операция логического отрицания. Производится над одним операндом и возвращает true, если операнд равен false. Если операнд равен true, то операция возвращает false: bool a = true; bool b = !a; // false ^ - Операция исключающего ИЛИ. Возвращает true, если либо первый, либо второй операнд (но не одновременно) равны true, иначе возвращает false bool x5 = (5 6) ^ (4 // 5 6 - false, 4 " width="640"
&& - Операция логического умножения. Возвращает true, если оба операнда одновременно равны true.
bool x1 = (5 6) && (4
// 5 6 - false, 4
bool x2 = (5
// 5 6 - true, поэтому возвращается true
! - Операция логического отрицания. Производится над одним операндом и возвращает true, если операнд равен false. Если операнд равен true, то операция возвращает false:
bool a = true;
bool b = !a; // false
^ - Операция исключающего ИЛИ. Возвращает true, если либо первый, либо второй операнд (но не одновременно) равны true, иначе возвращает false
bool x5 = (5 6) ^ (4
// 5 6 - false, 4
Операции | и || (а также & и && ) выполняют похожие
действия, но они не равнозначны.
В выражении z=x|y; будут вычисляться оба значения - x и y.
В выражении z=x||y ; сначала будет вычисляться значение
x, и если оно равно true, то вычисление значения y уже
смысла не имеет, так как в любом случае уже z будет
равно true. Значение y будет вычисляться только в том
случае, если x равно false.
То же самое для операций &/&& .
В выражении z=x&y; будут вычисляться оба значения - x и
y.
В выражении z=x&&y ; сначала будет вычисляться
значение x, и если оно равно false, то вычисление значения
y смысла не имеет, так как в любом случае z будет равно false.
Значение y будет вычисляться только в том случае, если
равно true.
Поэтому операции || и && более удобны в вычислениях, так
как позволяют сократить время на вычисление значения
выражения, и тем самым повышают производительность. А
операции | и & больше подходят для выполнения
поразрядных операций над числами.
Математические функции (класс Math)Класс Math
Для выполнения различных математических операций в библиотеке классов .NET предназначен класс Math .
Методы класса Math:
Abs(double value): возвращает абсолютное значение для аргумента value
double result = Math.Abs(-12.4); // 12.4
Acos(double value ) : возвращает арккосинус value. Параметр value должен иметь значение от -1 до 1
double result = Math.Acos(1); // 0
Asin(double value) : возвращает арксинус value. Параметр value должен иметь значение от -1 до 1
Atan(double value): возвращает арктангенс value
BigMul(int x, int y) : возвращает произведение x * y в виде объекта long
double result = Math.BigMul(100, 9340); // 934000 Ceiling(double value): возвращает наименьшее целое число с плавающей точкой, которое не меньше value
double result = Math.Ceiling(2.34); // 3
Cos(double d) : возвращает косинус угла d
Cosh(double d) : возвращает гиперболический косинус угла d
DivRem(int a, int b, out int result) : возвращает результат от деления a/b, а остаток помещается в параметр result
int result;
int div = Math.DivRem(14, 5, out result);
//result = 4
// div = 2
Exp(double d) : возвращает основание натурального логарифма, возведенное в степень d
Floor(decimal d) : возвращает наибольшее целое число, которое не больше d
double result = Math.Floor(2.56); // 2
IEEERemainder(double a, double b) : возвращает остаток от деления a на b
double result = Math.IEEERemainder(26, 4); // 2 = 26-24
Log(double d) : возвращает натуральный логарифм числа d
Log(double a, double newBase) : возвращает логарифм числа a по основанию newBase
Log10(double d) : возвращает десятичный логарифм числа d
Max(double a, double b) : возвращает максимальное число из a и b
Min(double a, double b) : возвращает минимальное число из a и b
Pow(double a, double b) : возвращает число a, возведенное в степень b
Round(double d) : возвращает число d, округленное до ближайшего целого числа
double result1 = Math.Round(20.56); // 21
double result2 = Math.Round(20.46); //20
Round(double a, round b) : возвращает число a, округленное до определенного количества знаков после запятой, представленного параметром b
double result1 = Math.Round(20.567, 2); // 20,57
double result2 = Math.Round(20.463, 1); //20,5
Sign(double value) : возвращает число 1, если число value положительное, и -1, если значение value отрицательное. Если value равно 0, то возвращает 0
int result1 = Math.Sign(15); // 1
int result2 = Math.Sign(-5); //-1
Sin(double value) : возвращает синус угла value
Sinh(double value) : возвращает гиперболический синус угла value
Sqrt(double value) : возвращает квадратный корень числа value
double result1 = Math.Sqrt(16); // 4
Tan(double value) : возвращает тангенс угла value
Tanh(double value) : возвращает гиперболический тангенс угла value
Truncate(double value) : отбрасывает дробную часть числа value, возвращаяя лишь целое значние
double result = Math.Truncate(16.89); // 16
Также класс Math определяет две константы: Math.E и Math.PI .
Например , вычислим площадь круга:
Console.WriteLine("Введите радиус круга");
double radius = Double.Parse(Console.ReadLine());
double area = Math.PI * Math.Pow(radius, 2); Console.WriteLine(" Площадь круга с радиусом {0} равна {1}", radius, area);
Консольный вывод:
Введите радиус круга
20
Площадь круга с радиусом 20 равна 1256,63706143592