EMZETT.
Login

Arithmetic Operators (Arithmetische Operatoren)

Kurz: Operatoren für die vier Grundrechenarten plus Modulo (Rest einer Division) — +, -, *, /, %.

Genauer: Der Modulo-Operator (%) liefert den Rest einer Ganzzahldivision und wird häufig genutzt, um z. B. zu prüfen, ob eine Zahl gerade ist (zahl % 2 == 0). Bei der Division zweier Ganzzahlen wird das Ergebnis in vielen Sprachen ebenfalls auf eine Ganzzahl abgeschnitten (kein automatisches Runden) — ein häufiger Anfängerfehler, wenn eigentlich ein Dezimalergebnis erwartet wird.

Im Detail

7 + 3   # 10
7 - 3   # 4
7 * 3   # 21
7 / 3   # 2.333... (Python: "echte" Division)
7 // 3  # 2 (Python: Ganzzahldivision, explizit)
7 % 3   # 1 (Rest der Division)

Viele Sprachen (z. B. Java, C) unterscheiden bei / selbst nach dem Datentyp: 7 / 3 ergibt bei zwei int-Operanden 2 (der Nachkommateil wird einfach abgeschnitten, nicht gerundet), während 7.0 / 3 als double-Division korrekt 2.333... liefert. Das ist eine der häufigsten stillen Fehlerquellen für Einsteiger, weil kein Fehler oder Warnung auftritt — das Ergebnis ist einfach nur falsch, wenn man eine Kommazahl erwartet hatte.

Modulo hat noch mehr praktische Anwendungen als nur die Gerade-/Ungerade-Prüfung:

index % array_laenge   // "wrap-around": Index bleibt immer im gültigen Bereich (z. B. Ringpuffer)
sekunden % 60           // Umrechnung Sekunden -> Minuten:Sekunden
zahl % 10               // letzte Ziffer einer Zahl extrahieren

Bei negativen Zahlen verhält sich Modulo je nach Sprache unterschiedlich — in manchen Sprachen (Python) hat das Ergebnis immer dasselbe Vorzeichen wie der Divisor, in anderen (Java, C) dasselbe Vorzeichen wie der Dividend. -7 % 3 ergibt in Python 2, in Java -1. Wer mit negativen Zahlen modulo rechnet, sollte das für die verwendete Sprache explizit nachschlagen statt sich auf ein universelles Verhalten zu verlassen.

Arithmetische Operatoren folgen der bekannten Punkt-vor-Strich-Regel (siehe Operator-Priorität) — *, / und % binden stärker als + und -.

Integer-Overflow

Ganzzahl-Datentypen haben eine feste Bitbreite und damit einen begrenzten Wertebereich (siehe byte, long) — rechnet man über diese Grenze hinaus, “überläuft” der Wert und springt (je nach Sprache) auf den kleinstmöglichen Wert zurück, statt einen Fehler zu werfen:

// 32-Bit int, Maximalwert 2147483647
maxWert + 1   // ergibt -2147483648, NICHT 2147483648 - stiller Fehler!

Manche Sprachen (Python) haben dieses Problem gar nicht, weil Ganzzahlen dort automatisch beliebig groß werden können; andere (Java, C, Rust im Release-Modus) lassen den Überlauf ohne Warnung durchlaufen, was zu einer der klassischsten, am schwersten zu findenden Fehlerklassen in älterer Software zählt — u. a. Ursache mehrerer bekannter Sicherheitslücken, weil ein überlaufener Wert z. B. eine Längenprüfung unbemerkt aushebeln kann.

Gleitkomma-Ungenauigkeit

Bei Dezimalzahlen (siehe Gleitkommazahl) führt die binäre Speicherung dazu, dass viele auf den ersten Blick “einfache” Dezimalwerte nicht exakt darstellbar sind:

0.1 + 0.2   # ergibt 0.30000000000000004, nicht exakt 0.3

Das ist kein Bug einer bestimmten Sprache, sondern eine Eigenschaft des IEEE-754-Gleitkommaformats, das praktisch alle modernen Sprachen verwenden. Für Geldbeträge oder andere Werte, bei denen exakte Dezimalgenauigkeit zählt, verwendet man deshalb dedizierte Dezimaltypen (BigDecimal in Java, Decimal in Python/C#) statt normaler float/double-Werte.

Operator-Überladung

In manchen Sprachen (C++, Python, C#) lässt sich definieren, was +, - usw. für selbstdefinierte Typen bedeuten sollen (“Operator Overloading”) — z. B. damit zwei Vektor-Objekte mit v1 + v2 addiert werden können, statt eine Methode wie v1.addiere(v2) aufrufen zu müssen. Das kann Code intuitiver lesbar machen, wird aber bei missbräuchlicher Nutzung (z. B. + überladen, um etwas völlig Unerwartetes zu tun) schnell verwirrend — die meisten Style-Guides empfehlen, Operatoren nur so zu überladen, dass ihr Verhalten der mathematischen Intuition entspricht.

Siehe auch: Operatoren, Operator-Priorität