Udostępnij przez


Operatory arytmetyczne (odwołanie w C#)

Następujące operatory wykonują operacje arytmetyczne z operandami typów liczbowych:

Wszystkie typy liczb całkowitych i zmiennoprzecinkowych obsługują te operatory.

Typy int, uint, longi ulong definiują wszystkie te operatory. Inne typy całkowite (sbyte, byte, short, ushort i char) definiują tylko operatory ++ i --. W przypadku innych operatorów, jeśli używasz typów całkowitych sbyte, , shortbyte, ushortlub char jako operandów, wartości są konwertowane na int typ, a typ wyniku to int. Jeśli operandy są różnymi typami całkowitymi lub zmiennoprzecinkowymi, 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.

Dokumentacja języka C# zawiera ostatnio wydaną wersję języka C#. Zawiera również początkową dokumentację dla funkcjonalności w publicznych wersjach testowych nadchodzącego wydania języka.

Dokumentacja identyfikuje dowolną funkcję po raz pierwszy wprowadzoną w ostatnich trzech wersjach języka lub w bieżącej publicznej wersji zapoznawczej.

Wskazówka

Aby dowiedzieć się, kiedy funkcja została po raz pierwszy wprowadzona w języku C#, zapoznaj się z artykułem dotyczącym historii wersji języka C#.

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ą xprzed 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ą xpo 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 dostępny w dwóch formularzach: operator dekrementacji postfiksu, x--i operator dekrementacji prefiksu, --x.

Operator dekrementacji przyrostkowej

Wynik x-- jest wartością xprzed 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ą xpo 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 floattypu , doublelub 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

floatW przypadku typów / , doublei decimal operator zwraca iloraz 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 operand ma decimalwartość , drugi operand nie może być float ani double, ponieważ ani nie floatdouble ma niejawnej konwersji 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 — \frac{a}{b} \times b$. Znak pozostałej części niezerowej jest zgodny ze znakiem 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, pasuje do znaku x.
  • Wartość z bezwzględna pochodzi z obliczenia $|x| — n \times |y|$, gdzie n jest największą liczbą całkowitą mniejszą lub równą $\frac{|x|}{|y|}$. W tym miejscu wartości $|x|$ i $|y|$ reprezentują odpowiednio wartości x bezwzględne i y.

Uwaga

Ta metoda obliczania reszty jest podobna do metody 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#.

W przypadku decimal operandów operator % reszty działa tak samo jak operator resztySystem.Decimal typu.

W poniższym przykładzie pokazano, jak operator reszty zachowuje się z operandami zmiennoprzecinkowych:

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 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 , aby usunąć delegata. Aby uzyskać więcej informacji, zobacz - operatory i -=.

Przypisanie złożone

Dla operatora opbinarnego wyrażenie przypisania złożonego formularza

x op= y

Jest odpowiednikiem

x = x op y

Z tą różnicą, że x jest obliczana 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 Tx. W takim przypadku, jeśli op jest wstępnie zdefiniowanym operatorem, a wynik operacji jest jawnie konwertowany na typ Tx, 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 porządkują od najwyższego pierwszeństwa do najniższego pierwszeństwa:

  • Operatory przyrostka przyrostkowego x++ i dekrementacji x--
  • Operatory inkrementacji i dekrementacji ++x prefiksu oraz operatory jednoargumentowe i - jednoargumentowe --x+
  • Mnożenie *operatorów , /, i %
  • Operatory i + addytywne -

Operatory arytmetyczne binarne są asocjacyjne po lewej stronie. Oznacza to, że kompilator ocenia operatory o tym samym poziomie pierwszeństwa 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.

Uwaga

Podział liczby całkowitej ma specjalny przypadek, w którym ArithmeticException można go zgłosić nawet w nieznakowanym kontekście. Gdy lewy operand jest minimalną wartością typu liczby całkowitej ze znakiem (int.MinValue lub long.MinValue), a prawy operand to -1, wynik nie może być reprezentowany w typie docelowym. W tym przypadku środowisko uruchomieniowe platformy .NET zgłasza błąd ArithmeticException , jak pokazano w poniższym przykładzie:

int a = int.MinValue;
int b = -1;
try
{
    int c = unchecked(a / b);
}
catch (ArithmeticException)
{
    Console.WriteLine($"Overflow occurred when dividing {a} by {b}.");
}

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 przy użyciu float typów i double nigdy nie zgłaszają wyjątku. Wynik operacji arytmetycznych przy użyciu tych typów 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 w reprezentacji liczb zmiennoprzecinkowych i arytmetycznych zmiennoprzecinkowych błędy zaokrąglenia mogą wystąpić w obliczeniach używających typów zmiennoprzecinkowych. Wynik wyrażenia może się różnić 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

Można przeciążyć operatory arytmetyczne jednoargumentowe (, --, +, i -) oraz binarne (++*, /, %+, i -) dla typu zdefiniowanego przez użytkownika. Przeciążenie operatora binarnego oznacza również niejawne przeciążenie odpowiedniego operatora przypisania złożonego. Począwszy od języka C# 14, typ zdefiniowany przez użytkownika może jawnie przeciążać operatory przypisania złożonego (op=), aby zapewnić wydajniejszą implementację. Zazwyczaj typ przeciąża te operatory, ponieważ wartość może być zaktualizowana bezpośrednio, zamiast przypisywać nową instancję do przechowywania wyniku operacji. Jeśli typ nie zapewnia jawnego przeciążenia, kompilator generuje niejawne przeciążenie.

Operatory zaznaczone przez użytkownika

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 kontekst wywołuje operatora zaznaczonego, a niezaznaczone kontekst wywołuje operatora bez checked modyfikatora.

Podczas definiowania obu wersji operatora ich zachowanie różni się tylko wtedy, gdy wynik operacji jest zbyt duży, aby reprezentować w typie 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 przypisania złożonego *=, /=, += i -= (C# 14 i nowsze)
  • Operatory konwersji jawnej

Uwaga

Modyfikator checked nie ma wpływu na kontekst sprawdzania przepełnienia w jego treści. 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#:

Zobacz też