Arithmetische Operatoren (C#-Referenz)

Die folgenden Operatoren führen arithmetische Operationen mit Operanden des numerischen Typs aus:

Diese Operatoren werden alle von numerischen Ganzzahl- und Gleitkommatypen unterstützt.

Bei integralen Typen werden diese Operatoren (außer den Operatoren ++ und --) für die Typen int, uint, long und ulong definiert. Wenn Operanden andere integrale Typen aufweisen (sbyte, byte, short, ushort oder char), werden ihre Werte in den Typ int konvertiert. Hierbei handelt es sich auch um den Ergebnistyp einer Operation. Wenn Operanden abweichende integrale Typen oder Gleitkommatypen aufweisen, werden ihre Werte in den am besten geeigneten enthaltenden Typ konvertiert, falls solch ein Typ vorhanden ist. Weitere Informationen finden Sie im Abschnitt Numerische Heraufstufungen der Spezifikation für die Sprache C#. Die ++- und ---Operatoren werden für alle numerischen integralen und Gleitkommatypen sowie den char-Typ definiert. Der Ergebnistyp eines zusammengesetzten Zuweisungsausdrucks ist der Typ des linken Operanden.

Inkrementoperator ++

Der unäre Inkrementoperator (++) erhöht seinen Operanden um 1. Der Operand muss eine Variable, ein Eigenschaftenzugriff oder ein Indexerzugriff sein.

Der Inkrementoperator wird in zwei Formen unterstützt: als Postfix-Inkrementoperator x++ und als Präfix-Inkrementoperator ++x.

Postfix-Operator für Inkrement

Das Ergebnis von x++ ist der Wert von x vor dem Vorgang, wie das folgende Beispiel zeigt:

int i = 3;
Console.WriteLine(i);   // output: 3
Console.WriteLine(i++); // output: 3
Console.WriteLine(i);   // output: 4

Präfixinkrement-Operator

Das Ergebnis von ++x ist der Wert von x nach dem Vorgang, wie das folgende Beispiel zeigt:

double a = 1.5;
Console.WriteLine(a);   // output: 1.5
Console.WriteLine(++a); // output: 2.5
Console.WriteLine(a);   // output: 2.5

Dekrementoperator --

Der unäre Dekrementoperator -- verringert seinen Operanden um 1. Der Operand muss eine Variable, ein Eigenschaftenzugriff oder ein Indexerzugriff sein.

Der Dekrementoperator wird in zwei Formen unterstützt: als Postfix-Dekrementoperator x-- und als Präfix-Dekrementoperator --x.

Postfix-Operator für Dekrement

Das Ergebnis von x-- ist der Wert von x vor dem Vorgang, wie das folgende Beispiel zeigt:

int i = 3;
Console.WriteLine(i);   // output: 3
Console.WriteLine(i--); // output: 3
Console.WriteLine(i);   // output: 2

Präfix-Dekrementoperator

Das Ergebnis von --x ist der Wert von x nach dem Vorgang, wie das folgende Beispiel zeigt:

double a = 1.5;
Console.WriteLine(a);   // output: 1.5
Console.WriteLine(--a); // output: 0.5
Console.WriteLine(a);   // output: 0.5

Unäre Plus- und Minusoperatoren

Der unäre +-Operator gibt den Wert seines Operanden zurück. Der unäre --Operator berechnet die numerische Negation des Operanden.

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

Der ulong-Typ unterstützt den unären --Operator nicht.

Multiplikationsoperator *

Der Multiplikationsoperator * berechnet das Produkt seiner Operanden:

Console.WriteLine(5 * 2);         // output: 10
Console.WriteLine(0.5 * 2.5);     // output: 1.25
Console.WriteLine(0.1m * 23.4m);  // output: 2.34

Der unäre *-Operator ist der Zeigerdereferenzierungsoperator.

Divisionsoperator /

Der Divisionsoperator / dividiert den linken Operanden durch den rechten Operanden.

Ganzzahldivision

Für die Operanden von Ganzzahltypen weist das Ergebnis des /-Operators einen Ganzzahltyp auf und ist gleich dem Quotienten der beiden Operanden, gerundet auf Null:

Console.WriteLine(13 / 5);    // output: 2
Console.WriteLine(-13 / 5);   // output: -2
Console.WriteLine(13 / -5);   // output: -2
Console.WriteLine(-13 / -5);  // output: 2

Um den Quotienten der beiden Operanden als Gleitkommazahl abzurufen, verwenden Sie den Typ float, double oder decimal:

Console.WriteLine(13 / 5.0);       // output: 2.6

int a = 13;
int b = 5;
Console.WriteLine((double)a / b);  // output: 2.6

Gleitkommadivision

Für die Typen float, double oder decimal ist das Ergebnis des /-Operators der Quotient der beiden Operanden:

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

Wenn einer der Operanden decimal lautet, kann ein anderer Operand weder float noch double sein, weil weder float noch double implizit zu decimal konvertiert werden können. Sie müssen den Operanden float oder double explizit zum Typ decimal konvertieren. Weitere Informationen zu Konvertierungen zwischen numerischen Typen finden Sie unter Built-in numeric conversions (Integrierte numerischer Konvertierungen).

Restoperator %

Der Restoperator % berechnet den Rest nach der Division seines linken Operanden durch den rechten Operanden.

Ganzzahliger Rest

Für Operanden von Ganzzahltypen entspricht das Ergebnis von a % b dem von a - (a / b) * b erzeugten Wert. Das Vorzeichen des Rests, der ungleich 0 (null) ist, ist wie im folgenden Beispiel gezeigt identisch mit dem Vorzeichen des linken Operanden:

Console.WriteLine(5 % 4);   // output: 1
Console.WriteLine(5 % -4);  // output: 1
Console.WriteLine(-5 % 4);  // output: -1
Console.WriteLine(-5 % -4); // output: -1

Verwenden Sie die Math.DivRem-Methode, wenn Sie sowohl Ganzzahldivision als auch Restergebnisse berechnen möchten.

Gleitkommarest

Für die Operanden float und double entspricht das Ergebnis von x % y für die endlichen Werte x und y dem Wert z, sodass:

  • das Vorzeichen von z dem Vorzeichen von x entspricht, sofern der Wert nicht 0 (null) ist.
  • der absolute Wert von z dem von |x| - n * |y| erzeugten Wert entspricht, wobei n der größtmöglichen Ganzzahl entspricht, die kleiner oder gleich |x| / |y| ist. Hierbei sind |x| und |y| jeweils die absoluten Werte von x und y.

Hinweis

Diese Methode zum Berechnen des Rests ist analog zu der Methode, die für ganzzahlige Operanden verwendet wird, unterscheidet sich jedoch von der IEEE 754-Spezifikation. Wenn Sie den Restvorgang benötigen, der der IEEE 754-Spezifikation entspricht, verwenden Sie die Methode Math.IEEERemainder.

Weitere Informationen zum Verhalten des %-Operators bei nicht begrenzten Operanden finden Sie im Abschnitt Restoperator der C#-Sprachspezifikation.

Der Restoperator % entspricht für die decimal-Operanden dem Restoperator vom Typ System.Decimal.

Im folgenden Beispiel wird das Verhalten des Restoperators mit Gleitkommaoperanden veranschaulicht:

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

Additionsoperator +

Der Additionsoperator + berechnet die Summe der Operanden:

Console.WriteLine(5 + 4);       // output: 9
Console.WriteLine(5 + 4.3);     // output: 9.3
Console.WriteLine(5.1m + 4.2m); // output: 9.3

Der +-Operator kann auch für die Zeichenfolgenverkettung und Delegatkombination verwendet werden. Weitere Informationen finden Sie im Artikel zu den Operatoren + und +=.

Subtraktionsoperator -

Der Subtraktionsoperator - subtrahiert den rechten Operanden vom linken:

Console.WriteLine(47 - 3);      // output: 44
Console.WriteLine(5 - 4.3);     // output: 0.7
Console.WriteLine(7.5m - 2.3m); // output: 5.2

Der --Operator kann auch für die Delegatentfernung verwendet werden. Weitere Informationen finden Sie im Artikel zu den Operatoren - und -=.

Verbundzuweisung

Bei einem binären Operator op entspricht ein Verbundzuweisungsausdruck der Form

x op= y

für die folgende Syntax:

x = x op y

außer dass x nur einmal überprüft wird.

Im folgenden Beispiel wird die Verwendung von Verbundzuweisungen mit arithmetischen Operatoren veranschaulicht:

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

Aufgrund von numerischen Höherstufungen kann das Ergebnis der Operation op ggf. nicht implizit in den Typ T von x konvertiert werden. In diesem Fall gilt Folgendes: Wenn op ein vordefinierter Operator ist und das Ergebnis der Operation explizit in den Typ T von x konvertiert werden kann, entspricht ein Verbundzuweisungsausdruck der Form x op= y dem Ausdruck x = (T)(x op y). Der einzige Unterschied ist, dass x nur einmal ausgewertet wird. Das folgende Beispiel veranschaulicht dieses Verhalten:

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

Im vorherigen Beispiel ist der Wert 44 das Ergebnis der Konvertierung des Werts 300 in den byte-Typ.

Hinweis

Im überprüften Überlaufüberprüfungskontext löst das vorherige Beispiel eine OverflowException aus. Weitere Informationen finden Sie im Abschnitt Überlauf der Integerarithmetik.

Die Operatoren += und -= können auch zum Abonnieren von Ereignissen und zum Kündigen eines Ereignisabonnements verwendet werden. Weitere Informationen finden Sie unter Abonnieren von Ereignissen und Kündigen von Ereignisabonnements.

Operatorrangfolge und Assoziativität

In der folgenden Liste sind die arithmetischen Operatoren beginnend mit dem höchsten Rangfolgenoperator absteigend sortiert:

  • Postfixinkrementoperator x++ und Postfixdekrementoperator x--
  • Präfixinkrementoperator ++x und Präfixdekrementoperator --x sowie unäre +- und --Operatoren
  • Multiplikative Operatoren *, / und %
  • Additive Operatoren + und -

Binäre arithmetische Operatoren sind linksassoziativ. Das bedeutet, dass Operatoren mit der gleichen Rangfolgenebene von links nach rechts ausgewertet werden.

Verwenden Sie Klammern (), wenn Sie die Reihenfolge der Auswertung ändern möchten, die durch Operatorrangfolge und Assoziativität festgelegt wird.

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

Die vollständige Liste der nach Rangfolgenebene sortierten C#-Operatoren finden Sie im Abschnitt Operatorrangfolge im Artikel C#-Operatoren.

Arithmetischer Überlauf und Division durch 0 (null)

Liegt das Ergebnis einer arithmetischen Operation außerhalb des Bereichs möglicher endlicher Werte des betreffenden numerischen Typs, hängt das Verhalten eines arithmetischen Operators vom Typ der Operanden ab.

Arithmetischer Überlauf bei ganzen Zahlen

Division ganzer Zahlen durch Null löst immer eine DivideByZeroException aus.

Im Fall eines arithmetischen Überlaufs bei ganzen Zahlen steuert der Kontext für Überlaufprüfungen, der checked oder unchecked sein kann, das sich ergebende Verhalten:

  • In einem aktivierten Kontext tritt bei einem Überlauf in einem konstanten Ausdruck ein Kompilierzeitfehler auf. Andernfalls wird, wenn die Operation zur Laufzeit ausgeführt wird, eine OverflowException-Ausnahme ausgelöst.
  • In einem deaktivierten Kontext wird das Ergebnis gekürzt, indem alle höherwertigen Bits verworfen werden, die nicht in den Zieltyp passen.

Neben den Anweisungen checked und unchecked können Sie mit den checked- und unchecked-Operatoren den Kontext für Überlaufprüfungen steuern, in dem ein Ausdruck ausgewertet wird:

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}.");
}

Standardmäßig erscheinen arithmetische Operationen in einem unchecked-Kontext.

Arithmetischer Überlauf bei Gleitkommatypen

Bei arithmetischen Operationen mit den Typen float und double wird nie eine Ausnahme ausgelöst. Das Ergebnis von arithmetischen Operationen mit diesen Typen können spezielle Werte sein, die unendliche und nicht numerische Zahlen darstellen:

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

Für Operanden vom Typ decimal löst ein arithmetischer Überlauf immer eine OverflowException-Ausnahme aus. Eine Division durch Null löst immer eine DivideByZeroException aus.

Rundungsfehler

Aufgrund allgemeiner Einschränkungen der Gleitkommadarstellung von reellen Zahlen und arithmetischer Gleitkommaoperatoren können in Berechnungen mit Gleitkommatypen Rundungsfehler auftreten. Das bedeutet, dass das generierte Ergebnis eines Ausdrucks vom erwarteten mathematischen Ergebnis abweichen kann. Im folgenden Beispiel werden einige solcher Fälle dargestellt:

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

Weitere Informationen finden Sie in den Hinweisen auf den Referenzseiten zu System.Double, System.Single oder System.Decimal.

Operatorüberladbarkeit

Ein benutzerdefinierter Typ kann die unären (++, --, + und -) und binären (*, /, %, + und -) arithmetischen Operatoren überladen. Wenn ein binärer Operator überladen ist, wird der zugehörige Verbundzuweisungsoperator implizit auch überladen. Ein benutzerdefinierter Typ kann einen Verbundzuweisungsoperator nicht explizit überladen.

Benutzerdefinierte checked-Operatoren

Ab C# 11 können Sie beim Überladen eines arithmetischen Operators das checked- Schlüsselwort verwenden, um die überprüfte Version dieses Operators zu definieren. Das folgende Beispiel zeigt, wie Sie dabei vorgehen müssen:

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);
    }
}

Wenn Sie einen checked-Operator definieren, müssen Sie auch den entsprechenden Operator ohne den checked-Modifizierer definieren. Der checked-Operator wird in einem checked- Kontext aufgerufen. Der Operator ohne den checked-Modifizierer wird in einem unchecked-Kontext aufgerufen. Wenn Sie den Operator ohne den checked-Modifizierer angeben, wird er sowohl in einem checked- als auch in einem unchecked-Kontext aufgerufen.

Wenn Sie beide Versionen eines Operators definieren, wird erwartet, dass sich ihr Verhalten nur dann unterscheidet, wenn das Ergebnis einer Operation wie folgt zu groß ist, um im Ergebnistyp darzustellen:

  • Ein checked-Operator löst eine OverflowException aus.
  • Ein Operator ohne den checked-Modifizierer gibt eine Instanz zurück, die ein gekürztes Ergebnis darstellt.

Informationen zum unterschiedlichen Verhalten der integrierten arithmetischen Operatoren finden Sie im Abschnitt Arithmetischer Überlauf und Division durch 0 (null).

Sie können den checked-Modifizierer nur verwenden, wenn Sie einen der folgenden Operatoren überladen:

Hinweis

Der Kontext für Überlaufüberprüfungen im Textkörper eines checked-Operators wird durch das Vorhandensein des checked-Modifizierers nicht beeinflusst. Der Standardkontext wird durch den Wert der CheckForOverflowUnderflow-Compileroption definiert. Verwenden Sie die checked- und unchecked-Anweisungen, um den Kontext für Überlaufüberprüfungen explizit anzugeben, wie das Beispiel am Anfang dieses Abschnitts veranschaulicht.

C#-Sprachspezifikation

Weitere Informationen finden Sie in den folgenden Abschnitten der C#-Sprachspezifikation:

Weitere Informationen