Operatory arytmetyczne (odwołanie w C#)

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

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 inttypów , uint, i .ulonglong Gdy operandy mają inne typy całkowite (sbyte, byte, short, ushortlub 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ą 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 obsługiwany w dwóch formach: 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 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 floatdouble, 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) * belement . 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 znak x.
  • Wartość bezwzględna to wartość z wygenerowana przez |x| - n * |y| lokalizację, w której n jest największą możliwą liczbą całkowitą, która jest mniejsza lub równa |x| / |y| wartościom |y| bezwzględnym x 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 opbinarnego 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 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 orders zaczynają się od najwyższego pierwszeństwa do najniższego:

  • Operatory przyrostka przyrostkowego x++ i dekrementacji x--
  • 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 uncheckedchecked .

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:

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#:

Zobacz też