Arithmetische Operatoren (C#-Referenz)
Die folgenden Operatoren führen arithmetische Operationen mit Operanden des numerischen Typs aus:
- Unäre Operatoren:
++(inkrementell),--(dekrementell),+(plus) und-(minus) - Binäre Operatoren:
*(Multiplikation),/(Division),%(Rest),+(Addition) und-(Subtraktion)
Diese Operatoren werden alle von numerischen Ganzzahl- und Gleitkommatypen unterstützt.
Ab C# 11 können Sie eine checked-Variante für Operatoren definieren, die von der Überlaufüberprüfung betroffen sind. Wenn Sie einen Operator definieren, müssen Sie auch einen checked Operator ohne das checked Schlüsselwort definieren. Weitere Informationen zu überprüften und nicht überprüften Operatoren finden Sie im Artikel zu arithmetischen Operatoren. Arithmetische Operatoren mit Ausnahme von % und unären +-Operatoren unterstützen einen checked-Operator. Im Allgemeinen wird erwartet, dass ein checked-Operator eine Ausnahme auslöst, wenn das Ergebnis einen Überlauf des Zieltyps verursacht. Ein nicht überprüfter Operator löst in der Regel keine Ausnahme aus. Das Überlaufverhalten hängt vom jeweiligen Typ ab. Einige Typen verwenden z. B. inttruncate oder Umschließungsverhalten. Andere Typen verwenden z. B. floatclamp für den Maximal- oder Minimalwert. Wieder andere Typen wie decimal lösen Ausnahmen auch in einem nicht überprüften Kontext aus. Die Typen in der .NET-Runtime folgen diesen Semantiken. Der Compiler erzwingt diese Anforderungen nicht, aber Entwickler sollten diese Richtlinien in ihren Typen befolgen. Der checked-Operator enthält das checked-Schlüsselwort. Der nicht überprüfte Operator enthält diesen Modifizierer nicht, wie das folgende Beispiel zeigt:
public struct Point
{
public int X { get; set; }
public int Y { get; set; }
public Point(int x, int y)
{
this.X = x;
this.Y = y;
}
public static Point operator checked + (Point left, Point right)
{
checked
{
var x = left.X + right.X;
var y = left.Y + right.Y;
return new Point(x, y);
}
}
public static Point operator +(Point left, Point right)
{
return new Point(left.X + right.X, left.Y + right.Y);
}
}
Im vorherigen Beispiel wird deklariert, dass der checked-Operator in einem checked-Kontext ausgeführt wird. Weitere Informationen zu checked- und unchecked-Kontexten finden Sie im Artikel zu überprüften und nicht überprüften Kontexten.
Wenn Sie einen Operator mit dem checked-Modifizierer bereitstellen, müssen Sie auch eine Implementierung dieses Operators ohne den checked-Modifizierer bereitstellen. Wenn Sie beide Versionen bereitstellen, wird der checked-Operator in einem checked-Kontext aufgerufen. Der Operator ohne checked-Modifizierer wird in einem unchecked-Kontext aufgerufen. Aus diesem Grund wird er in der Regel als nicht überprüfter Operator bezeichnet. Wenn Sie den Operator ohne das checked-Schlüsselwort bereitstellen, wird er sowohl in einem checked- als auch in einem unchecked-Kontext aufgerufen.
Diese Operatoren werden 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. ++, -- und alle zusammengesetzten arithmetischen Operatoren (z. B. +=), konvertieren ihre Argumente nicht in int oder weisen den Ergebnistyp als int aus.
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 xvor 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 xnach 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 xvor 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 xnach 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
zdem Vorzeichen vonxentspricht, sofern der Wert nicht 0 (null) ist. - der absolute Wert von
zdem von|x| - n * |y|erzeugten Wert entspricht, wobeinder größtmöglichen Ganzzahl entspricht, die kleiner oder gleich|x| / |y|ist. Hierbei sind|x|und|y|jeweils die absoluten Werte vonxundy.
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
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 Postfixdekrementoperatorx-- - Präfixinkrementoperator
++xund Präfixdekrementoperator--xsowie 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 ein Kontext für Überlaufprüfungen, der überprüft oder nicht überprüft (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 mithilfe der 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.
C#-Sprachspezifikation
Weitere Informationen finden Sie in den folgenden Abschnitten der C#-Sprachspezifikation:
- Postfix-Inkrementoperator und Postfix-Dekrementoperator
- Präfix-Inkrementoperator und Präfix-Dekrementoperator
- Unärer Plusoperator
- Unärer Minusoperator
- Multiplikationsoperator
- Divisionsoperator
- Restoperator
- Additionsoperator
- Subtraktionsoperator
- Verbundzuweisung
- The checked and unchecked operators (Checked- und Unchecked-Operatoren)
- Numerische Heraufstufungen