Operatory arytmetyczne (odwołanie w C#)
Następujące operatory wykonują operacje arytmetyczne z operandami typów liczbowych:
- Jednoargumentowe
++
(przyrost),--
(dekrementacja),+
(plus)i-
(minus) operatory - Operatory binarne
*
(mnożenie),/
(dzielenie), (pozostała),%
+
(dodawanie)i-
(odejmowanie)
Te operatory są obsługiwane przez wszystkie typy liczb całkowitych i zmiennoprzecinkowych .
W przypadku typów całkowitych te operatory (z wyjątkiem ++
operatorów i--
) są definiowane dla int
typów , uint
, i .ulong
long
Gdy operandy mają inne typy całkowite (sbyte
, byte
, short
, ushort
lub char
), ich wartości są konwertowane na int
typ, który jest również typem wyniku operacji. Gdy operandy mają różne typy całkowite lub zmiennoprzecinkowe, ich wartości są konwertowane na najbliższy typ zawierający, jeśli taki typ istnieje. Aby uzyskać więcej informacji, zobacz sekcję Promocje liczbowe specyfikacji języka C#. Operatory ++
i --
są definiowane dla wszystkich typów liczb całkowitych i zmiennoprzecinkowych oraz typu char . Typ wyniku wyrażenia przypisania złożonego jest typem operandu po lewej stronie.
Operator inkrementacji ++
Operator ++
przyrostu jednoargumentowego zwiększa operand o 1. Operand musi być zmienną, dostępem do właściwości lub dostępem indeksatora.
Operator inkrementacji jest obsługiwany w dwóch formularzach: operator przyrostka, x++
, i operator przyrostka przyrostka, ++x
.
Operator inkrementacji przyrostkowej
Wynik x++
jest wartością x
przed operacją, jak pokazano w poniższym przykładzie:
int i = 3;
Console.WriteLine(i); // output: 3
Console.WriteLine(i++); // output: 3
Console.WriteLine(i); // output: 4
Operator inkrementacji prefiksu
Wynik ++x
jest wartością x
po operacji, jak pokazano w poniższym przykładzie:
double a = 1.5;
Console.WriteLine(a); // output: 1.5
Console.WriteLine(++a); // output: 2.5
Console.WriteLine(a); // output: 2.5
Operator dekrementacji —
Operator --
dekrementacji jednoargumentowej dekrementuje operand o 1. Operand musi być zmienną, dostępem do właściwości lub dostępem indeksatora.
Operator dekrementacji jest obsługiwany w dwóch formach: operator dekrementacji postfiksu, x--
i operator dekrementacji prefiksu, --x
.
Operator dekrementacji przyrostkowej
Wynik x--
jest wartością x
przed operacją, jak pokazano w poniższym przykładzie:
int i = 3;
Console.WriteLine(i); // output: 3
Console.WriteLine(i--); // output: 3
Console.WriteLine(i); // output: 2
Operator dekrementacji prefiksu
Wynik --x
jest wartością x
po operacji, jak pokazano w poniższym przykładzie:
double a = 1.5;
Console.WriteLine(a); // output: 1.5
Console.WriteLine(--a); // output: 0.5
Console.WriteLine(a); // output: 0.5
Operatory jednoargumentowe plus i minus
Operator jednoargumentowy +
zwraca wartość operandu. Operator jednoargumentowy -
oblicza negację liczbową operandu.
Console.WriteLine(+4); // output: 4
Console.WriteLine(-4); // output: -4
Console.WriteLine(-(-4)); // output: 4
uint a = 5;
var b = -a;
Console.WriteLine(b); // output: -5
Console.WriteLine(b.GetType()); // output: System.Int64
Console.WriteLine(-double.NaN); // output: NaN
Typ ulong nie obsługuje operatora jednoargumentowego -
.
Operator mnożenia *
Operator *
mnożenia oblicza produkt swoich operandów:
Console.WriteLine(5 * 2); // output: 10
Console.WriteLine(0.5 * 2.5); // output: 1.25
Console.WriteLine(0.1m * 23.4m); // output: 2.34
Operator jednoargumentowy *
jest operatorem pośrednim wskaźnika.
Operator dzielenia /
Operator /
dzielenia dzieli lewy operand przez operand po prawej stronie.
Dzielenie liczb całkowitych
W przypadku operandów typów całkowitych wynik /
operatora jest typu całkowitego i równa się ilorazowi dwóch operandów zaokrąglonych w kierunku zera:
Console.WriteLine(13 / 5); // output: 2
Console.WriteLine(-13 / 5); // output: -2
Console.WriteLine(13 / -5); // output: -2
Console.WriteLine(-13 / -5); // output: 2
Aby uzyskać iloraz dwóch operandów jako liczbę zmiennoprzecinkową, użyj float
typu , double
lub decimal
:
Console.WriteLine(13 / 5.0); // output: 2.6
int a = 13;
int b = 5;
Console.WriteLine((double)a / b); // output: 2.6
Dzielenie zmiennoprzecinkowe
float
W przypadku typów , double
i decimal
wynik /
operatora jest ilorazem dwóch operandów:
Console.WriteLine(16.8f / 4.1f); // output: 4.097561
Console.WriteLine(16.8d / 4.1d); // output: 4.09756097560976
Console.WriteLine(16.8m / 4.1m); // output: 4.0975609756097560975609756098
Jeśli jeden z operandów to decimal
, inny operand nie może być ani float
double
, ponieważ ani ani float
nie double
jest niejawnie konwertowany na decimal
. Musisz jawnie przekonwertować float
argument lub double
operand na decimal
typ. Aby uzyskać więcej informacji na temat konwersji między typami liczbowymi, zobacz Wbudowane konwersje liczbowe.
Operator remainder %
Operator reszty %
oblicza resztę po podzieleniu operandu po lewej stronie przez operand prawego ręki.
Pozostała liczba całkowita
W przypadku operandów typów całkowitych wynik a % b
jest wartością wygenerowaną przez a - (a / b) * b
element . Znak pozostałej części niezerowej jest taki sam jak znak operandu po lewej stronie, jak pokazano w poniższym przykładzie:
Console.WriteLine(5 % 4); // output: 1
Console.WriteLine(5 % -4); // output: 1
Console.WriteLine(-5 % 4); // output: -1
Console.WriteLine(-5 % -4); // output: -1
Math.DivRem Użyj metody , aby obliczyć zarówno dzielenie całkowite, jak i pozostałe wyniki.
Pozostała część zmiennoprzecinkowa
float
W przypadku operandów i double
wynik x % y
dla skończonego x
elementu i y
jest wartością z
taką, że
- Znak
z
, jeśli niezerowy, jest taki sam jak znakx
. - Wartość bezwzględna to wartość
z
wygenerowana przez|x| - n * |y|
lokalizację, w którejn
jest największą możliwą liczbą całkowitą, która jest mniejsza lub równa|x| / |y|
wartościom|y|
bezwzględnymx
i|x|
y
, odpowiednio.
Uwaga
Ta metoda przetwarzania reszty jest analogiczna do tej używanej dla operandów całkowitych, ale różni się od specyfikacji IEEE 754. Jeśli potrzebujesz operacji pozostałej, która jest zgodna ze specyfikacją IEEE 754, użyj Math.IEEERemainder metody .
Aby uzyskać informacje o zachowaniu %
operatora z operandami innych niż skończone, zobacz sekcję Operator Remainder specyfikacji języka C#.
decimal
W przypadku operandów operator %
reszty jest odpowiednikiem operatora pozostałego System.Decimal typu.
W poniższym przykładzie pokazano zachowanie operatora pozostałego z operandami zmiennoprzecinkowymi:
Console.WriteLine(-5.2f % 2.0f); // output: -1.2
Console.WriteLine(5.9 % 3.1); // output: 2.8
Console.WriteLine(5.9m % 3.1m); // output: 2.8
Operator dodawania +
Operator +
dodawania oblicza sumę operandów:
Console.WriteLine(5 + 4); // output: 9
Console.WriteLine(5 + 4.3); // output: 9.3
Console.WriteLine(5.1m + 4.2m); // output: 9.3
Możesz również użyć +
operatora do łączenia ciągów i kombinacji delegatów. Aby uzyskać więcej informacji, zobacz +
artykuł i +=
operatory .
Operator odejmowania —
Operator -
odejmowania odejmuje swój operand po prawej stronie od operandu po lewej stronie:
Console.WriteLine(47 - 3); // output: 44
Console.WriteLine(5 - 4.3); // output: 0.7
Console.WriteLine(7.5m - 2.3m); // output: 5.2
Możesz również użyć -
operatora do usunięcia delegata. Aby uzyskać więcej informacji, zobacz -
artykuł i -=
operatory .
Przypisanie złożone
Dla operatora op
binarnego wyrażenie przypisania złożonego formularza
x op= y
jest równoważny
x = x op y
z wyjątkiem tego, że x
jest obliczany tylko raz.
W poniższym przykładzie pokazano użycie przypisania złożonego z operatorami arytmetycznymi:
int a = 5;
a += 9;
Console.WriteLine(a); // output: 14
a -= 4;
Console.WriteLine(a); // output: 10
a *= 2;
Console.WriteLine(a); // output: 20
a /= 4;
Console.WriteLine(a); // output: 5
a %= 3;
Console.WriteLine(a); // output: 2
Ze względu na promocje liczbowe wynik op
operacji może nie być niejawnie konwertowany na typ T
x
. W takim przypadku, jeśli op
jest wstępnie zdefiniowanym operatorem, a wynik operacji jest jawnie konwertowany na typ T
x
, wyrażenie przypisania złożonego formularza x op= y
jest równoważne x = (T)(x op y)
, z wyjątkiem tego, że x
jest obliczany tylko raz. W poniższym przykładzie pokazano, że zachowanie:
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
W poprzednim przykładzie wartość 44
jest wynikiem konwersji wartości 300
na byte
typ.
Uwaga
W zaznaczonym kontekście sprawdzania przepełnienia powyższy przykład zgłasza błąd OverflowException. Aby uzyskać więcej informacji, zobacz sekcję Przepełnienie arytmetyczne liczby całkowitej.
Operatory i -=
są również używane +=
do subskrybowania i anulowania subskrypcji zdarzenia, odpowiednio. Aby uzyskać więcej informacji, zobacz Jak subskrybować i anulować subskrypcję zdarzeń.
Pierwszeństwo operatora i kojarzenie
Następujące operatory arytmetyczne orders zaczynają się od najwyższego pierwszeństwa do najniższego:
- Operatory przyrostka przyrostkowego
x++
i dekrementacjix--
- Przyrostek i dekrementacja
++x
--x
oraz operatory jednoargumentowe i-
jednoargumentowe+
- Mnożenie
*
operatorów ,/
, i%
- Operatory i
-
addytywne+
Operatory arytmetyczne binarne są asocjacyjne po lewej stronie. Oznacza to, że operatory z tym samym poziomem pierwszeństwa są oceniane od lewej do prawej.
Użyj nawiasów, ()
, aby zmienić kolejność oceny narzuconą przez pierwszeństwo operatora i kojarzenie.
Console.WriteLine(2 + 2 * 2); // output: 6
Console.WriteLine((2 + 2) * 2); // output: 8
Console.WriteLine(9 / 5 / 2); // output: 0
Console.WriteLine(9 / (5 / 2)); // output: 4
Aby uzyskać pełną listę operatorów języka C# uporządkowanych według poziomu pierwszeństwa, zobacz sekcję Pierwszeństwo operatora w artykule Operatory języka C#.
Przepełnienie arytmetyczne i dzielenie według zera
Gdy wynik operacji arytmetycznej znajduje się poza zakresem możliwych wartości skończonych zaangażowanego typu liczbowego, zachowanie operatora arytmetycznego zależy od typu jego operandów.
Przepełnienie arytmetyczne liczb całkowitych
Dzielenie liczb całkowitych przez zero zawsze zgłasza wartość DivideByZeroException.
Jeśli występuje przepełnienie arytmetyczne liczb całkowitych, kontekst sprawdzania przepełnienia, który można sprawdzić lub usunąć zaznaczenie, kontroluje wynikowe zachowanie:
- W zaznaczonym kontekście, jeśli przepełnienie występuje w wyrażeniu stałym, wystąpi błąd czasu kompilacji. W przeciwnym razie, gdy operacja jest wykonywana w czasie wykonywania, OverflowException jest zgłaszany.
- W niezaznaczonym kontekście wynik jest obcinany przez odrzucenie wszystkich bitów o wysokiej kolejności, które nie mieszczą się w typie docelowym.
Oprócz zaznaczonych i niezaznaczonej instrukcji można użyć checked
operatorów i unchecked
do kontrolowania kontekstu sprawdzania przepełnienia, w którym jest oceniane wyrażenie:
int a = int.MaxValue;
int b = 3;
Console.WriteLine(unchecked(a + b)); // output: -2147483646
try
{
int d = checked(a + b);
}
catch(OverflowException)
{
Console.WriteLine($"Overflow occurred when adding {a} to {b}.");
}
Domyślnie operacje arytmetyczne występują w nieznakowanym kontekście.
Przepełnienie arytmetyczne zmiennoprzecinkowe
Operacje arytmetyczne z float
typami i double
nigdy nie zgłaszają wyjątku. Wynik operacji arytmetycznych z tymi typami może być jedną z specjalnych wartości reprezentujących nieskończoność, a nie liczbę:
double a = 1.0 / 0.0;
Console.WriteLine(a); // output: Infinity
Console.WriteLine(double.IsInfinity(a)); // output: True
Console.WriteLine(double.MaxValue + double.MaxValue); // output: Infinity
double b = 0.0 / 0.0;
Console.WriteLine(b); // output: NaN
Console.WriteLine(double.IsNaN(b)); // output: True
W przypadku operandów decimal
typu arytmetyczne przepełnienie zawsze zgłasza wartość OverflowException. Dzielenie przez zero zawsze zgłasza wartość DivideByZeroException.
Błędy zaokrąglania
Ze względu na ogólne ograniczenia reprezentacji liczb rzeczywistych i arytmetycznych zmiennoprzecinkowych błędy zaokrąglenia mogą wystąpić w obliczeniach z typami zmiennoprzecinkowych. Oznacza to, że wygenerowany wynik wyrażenia może różnić się od oczekiwanego wyniku matematycznego. W poniższym przykładzie pokazano kilka takich przypadków:
Console.WriteLine(.41f % .2f); // output: 0.00999999
double a = 0.1;
double b = 3 * a;
Console.WriteLine(b == 0.3); // output: False
Console.WriteLine(b - 0.3); // output: 5.55111512312578E-17
decimal c = 1 / 3.0m;
decimal d = 3 * c;
Console.WriteLine(d == 1.0m); // output: False
Console.WriteLine(d); // output: 0.9999999999999999999999999999
Aby uzyskać więcej informacji, zobacz uwagi na stronach referencyjnych System.Double, System.Single lub System.Decimal .
Przeciążenie operatora
Typ zdefiniowany przez użytkownika może przeciążać operatory arytmetyczne jednoargumentowe (++
, --
, , +
i -
) oraz binarne (*
, /
, +
%
, i -
). Gdy operator binarny jest przeciążony, odpowiedni operator przypisania złożonego jest również niejawnie przeciążony. Typ zdefiniowany przez użytkownika nie może jawnie przeciążyć operatora przypisania złożonego.
Operatory zaznaczone przez użytkownika
Począwszy od języka C# 11, gdy przeciążysz operator arytmetyczny, możesz użyć checked
słowa kluczowego , aby zdefiniować sprawdzoną wersję tego operatora. W poniższym przykładzie pokazano, jak to zrobić:
public record struct Point(int X, int Y)
{
public static Point operator checked +(Point left, Point right)
{
checked
{
return new Point(left.X + right.X, left.Y + right.Y);
}
}
public static Point operator +(Point left, Point right)
{
return new Point(left.X + right.X, left.Y + right.Y);
}
}
Podczas definiowania operatora zaznaczonego należy również zdefiniować odpowiedni operator bez checked
modyfikatora. Sprawdzony operator jest wywoływany w zaznaczonym kontekście; operator bez checked
modyfikatora jest wywoływany w nieznakowanym kontekście. Jeśli podasz operator bez checked
modyfikatora, zostanie on wywołany zarówno w kontekście, jak i unchecked
checked
.
Podczas definiowania obu wersji operatora oczekiwane jest, że ich zachowanie różni się tylko wtedy, gdy wynik operacji jest zbyt duży, aby reprezentować typ wyniku w następujący sposób:
- Sprawdzony operator zgłasza błąd OverflowException.
- Operator bez
checked
modyfikatora zwraca wystąpienie reprezentujące obcięty wynik.
Aby uzyskać informacje na temat różnicy w zachowaniu wbudowanych operatorów arytmetycznych, zobacz sekcję Przepełnienie arytmetyczne i dzielenie według zera .
Modyfikator można używać checked
tylko wtedy, gdy przeciążysz dowolny z następujących operatorów:
- Jednoargumentowe
++
operatory ,--
i-
- Operatory binarne
*
,/
,+
i-
- Operatory konwersji jawnej
Uwaga
Kontekst sprawdzania przepełnienia w treści operatora zaznaczonego nie ma wpływu na obecność checked
modyfikatora. Domyślny kontekst jest definiowany przez wartość opcji kompilatora CheckForOverflowUnderflow . Użyj instrukcji checked
iunchecked
, aby jawnie określić kontekst sprawdzania przepełnienia, jak pokazano w przykładzie na początku tej sekcji.
specyfikacja języka C#
Aby uzyskać więcej informacji, zobacz następujące sekcje specyfikacji języka C#:
- Operatory przyrostka przyrostkowego i dekrementacji
- Operatory przyrostkowe i dekrementacji prefiksu
- Jednoargumentowy operator plus
- Jednoargumentowy operator minus
- Operator mnożenia
- Operator dzielenia
- Operator Remainder
- Operator dodawania
- Operator odejmowania
- Przypisanie złożone
- Zaznaczone i niezaznaczone operatory
- Promocje liczbowe