ТЕМА 9: Операции и изрази
В C# са определени следните операции:
+ - бинарно събиране и унарен +;
– - бинарно изваждане и унарен –;
* - умножение;
/ - деление;
% - остатък от целочислено деление;
++ - увеличаване с единица;
–– - намаляване с единица.
+, –, *, / могат да се прилагат на всеки вграден тип данни.
Ако операндите при / са от цял тип, то делението е целочислено. В C# при операцията % операндите могат да са както от цял, така и от float тип.
Операциите ++ и – – могат да се записват както преди операнда, така и след него като постфикс.
++x и x++ са еквивалентни на x=x+1
– –x и x– – са еквивалентни на x=x – 1
Ако след тези операнди в израз се изпълняват и други операции тогава ++x и x++ се различават. Ако операцията е преди операнда то C# променя с единица променливата преди да се използва в останалата част от израза.
int x, y;
x = 10;
y = ++x; //x=x+1; y=x;
Но ако операцията е след операнда, то C# променя с единица стойността на операнда след като тази променлива е използвана в останалата част на израза.
y=x++; //y=x; x=X+1;
В C# се използват следни операции за сравнение:
==, !=, <, >==, >, <=;
& - and, логическо „и” (логическо умножение);
| - or, логическо „или” (логическо събиране);
^ - xor;
&& - бърза операция „и” (short-circuit and);
|| - бърза операция „или” (short-circuit or);
! – not.
Резултатът от изпълнението на операциите за сравнение и на логическите операции е стойност от тип bool.
В C# операциите == и != могат да се прилагат с всички обекти. Операциите за сравнение могат да се прилагат към типове, чиито стойности са наредени, следователно те могат да се прилагат към всички числови типове данни, но те не могат да се прилагат към стойности от булев тип false и true, тъй като те в C# не са наредени (в C/ C++ false<true).
За логически операции операндите трябва да са от булев тип. Бързите операции пресмятат (оценяват) втория операнд само тогава, когато резултатът от изпълнението на операцията не може да се определи единствено с пресмятане на първия операнд.
Ако при изпълнение на операцията && първият операнд има стойност false, то резултатът ще е false независимо от стойността на втория операнд. При || ако първия операнд има стойност true, то резултатът ще е true независимо от втория операнд. Съществува разлика между & и | и && и ||. Тя се изразява в това, че при обикновените операции винаги се оценяват и първия и втория операнд. При бързите втория се оценява само при необходимост. В общия случай използването на && и || води до по-бързо изпълнение на програмата.
Ще разгледаме пример при който използването на && води до предотвратяване на деление на 0.
int n,d;
…
If(d!=0 && (n%d)==0)
{
Console.WriteLine(d+” е делител на ”+n);
}
//Понякога в операциите and и or винаги трябва да се оцени втория операнд”
int i=0; bool p;
…
If(p & ++i<100)
{
Console.WriteLine(“i=”+i);
}
Операцията за присвояване:
променлива = израз;
Типът на променливата трябва да е съвместим с типа на израза.
int x, y, z;
x = y = z = 34 + 66;
В C#, както и в C/C++, се използват съставни операции за присвояване с общ вид:
променлива операция=израз;
Те са съвместими с операциите +, –, *, /, %, &, |, ^.
Съставните операции имат две преимущества: те се записват по-кратко и се компилират по-бързо. Ако типовете на операндите при операция = са различни, то типа на израза от дясно се преобразува автоматично към типа на променливата отляво при условие че са изпълнение следните изисквания:
- двата типа са съвместими;
- допустимата стойност на типа от ляво обхваща допустимата стойност на типа от дясно (преобразуването е разширяващо).
Числените типове са съвместими помежду си. Числените типове bool, char и decimal не са съвместими помежду си.
long L;
double D;
D=L;//автоматично преобразуване от long в double
L=D;//не може автоматично (преобразуването не е разширяващо)
Когато не може да се извърши автоматичното преобразуването се използва явно преобразуване с помощта на операция, която има следния вид:
(тип)израз; – при изпълнение типа на израза се преобразува към „тип”
double x, y;
byte b;
int i;
char ch;
x=10.0;
y=3.0;
i=x/y; //грешка
i=(int)(x/y); //свиващо преобразуване към цяло число – реже се дробната част
b=(byte)i;
ch=(char)b; //между ch и b няма съвместимост
Израз в C# е синтактично и семантично допустима комбинация от константи, променливи, операции, обръщения към функции и методи и кръгли скоби. Съществува възможност в един израз да се използват две или повече различни типове данни, ако те са съвместими. Например в един израз могат да се използват данни от тип short и от тип long, тъй като са числени и съвместими. Различните типове се преобразуват към един и същи тип в съответствие с правилата за автоматично преобразуване на типовете в израз.
Ще разгледаме алгоритъма за преобразуване определен от аритметичните операции:
- Ако единия операнд е от тип decimal, то другия също се преобразува с изключение на long или double. Тогава възниква грешка.
- Ако единия операнд е double, то другия се преобразува към тип double.
- Ако единия операнд има тип float, то и другия се преобразува към float.
- Unsigned long – другия се преобразува към ulong, освен когато е short, long, signed byte или int. В такъв случай дава грешка.
- Long – другия се преобразува към long.
- Unsigned int, а другия signed byte, short, int – и двата стават long.
- Unsigned int – другия се преобразува към unsigned int.
- Ако от правилата от 1 до 7 не са приложими и двата стават int.
Ще обърнем внимание на някой моменти от алгоритъма. Не всички типове данни са съвместими, например: float или double в decimal или signed целочислена в unsigned long. За съвместяването трябва да се cast-ват. От последното правило следва, че всички стойности в един израз от тип char, sbyte, byte, short, ushort се преобразуват към int. Това означава, че за резултатът ще се разпределя памет, не по-малка от тази за int. Операндите при унарните операции, чиито диапазон е по-малък от този на int, стават на int. Освен това ако на операнд от тип unsigned int се присвои стойност по-малка от 0 , той се преобразува към long.
byte b; int i;
b=10;
i=b*b;
b=(byte)(b*b);
char ch1=’a’, ch2=’b’;
ch1=(char)(ch1+ch2);
…
int broi, suma;
double sr_uspeh;
….
sr_uspeh = (double)(suma/broi);
Таблица на приоритетите и асоциативността на операциите:
Операция |
асоциативност |
( ) [ ] |
-> |
Постфиксно ++ и -- |
<- |
! +(унарен) –(унарен) (тип) префиксно ++ и -- |
<- |
* / % |
-> |
+ - |
-> |
< <= > >= |
-> |
== != |
-> |
& |
-> |
^ |
-> |
| |
-> |
&& |
-> |
|| |
-> |
Операция = |
<- |
Програма за пресмятане на сумите за ежемесечно изплащане по взет кредит
using System;
class RegPay
{
public static void Main()
{
decimal Principal, IntRate, PayPerYear, NumYears, Payment;
decimal numer, denom;
double b, e; //b->oснова e->степенен показател в Pow()
Principal=10000.00m; //размер на кредита
IntRate=0.075m; //7.5% лихва
PayPerYear=12m; // изплащания на годинa
NumYears=5m; //срок за погасяване на кредита в години
numer=IntRate*(Principal/PayPerYear);
e=(double)-(PayPerYear*NumYears);
b=(double)(IntRate/PayPerYear) + 1;
denom=1-(decimal)Math.Pow(b, e);
Payment=numer/denom;
Console.WriteLine(“Сума за ежемесечно изплащане: {0:C}”, Payment);
}
}
В тази програма се извършват финансови пресмятания. Затова се използва тип decimal. Също така се демонстрира използването на операцията за явно преобразуване на типа и метода Pow от библиотеката на С#. Този метод реализира операцията повдигане в степен като и двата аргумента трябва да са от тип double и връщания резултат е от тип double.