In früheren Kursen wurde mir das beigebracht n % d = r
und darüber nachzudenken als n = d*q + r
wo d
ist der Teiler, q
ist der Quotient, und r
der Rest ist (wobei zu beachten ist, dass der Rest niemals negativ sein kann).
Also zum Beispiel -111 mod 11
ist 10
Weil -111 = -11*-11 + 10
(im Gegensatz zu -111 = -11*10 -1
da uns das einen negativen Rest geben würde).
Beim Drucken der Ergebnisse jedoch -111 % 11
, -1
ist das Ergebnis und nicht 10
. Wieso den? Ist das nicht technisch falsch?
Kurze Antwort:
Das garantiert der Standard (a/b)*b + a%b
ist gleich a
.
In C99 das Ergebnis der Teilung /
wird gegen Null abgeschnitten. Das Ergebnis von %
Betreiber wird in diesem Fall sicher sein, -1
.
In C89 das Ergebnis der Division /
kann bei negativen Operanden in beide Richtungen abgeschnitten werden. Also das Ergebnis von %
Bediener ist ebenfalls maschinenabhängig.
Lange Antwort:
Ab C99 6.5.5
5 Das Ergebnis des /-Operators ist der Quotient aus der Division des ersten Operanden durch den zweiten; das Ergebnis des %-Operators ist der Rest. Wenn der Wert des zweiten Operanden Null ist, ist das Verhalten in beiden Operationen undefiniert.
6 Wenn ganze Zahlen dividiert werden, ist das Ergebnis des /-Operators der algebraische Quotient, wobei alle Nachkommastellen verworfen werden. Wenn der Quotient a/b darstellbar ist, soll der Ausdruck (a/b)*b + a%b gleich a sein; andernfalls ist das Verhalten von a/b und a%b undefiniert.
Und die Fußnote auf derselben Seite, um zu erklären, wie /
funktioniert, da steht:
Dies wird oft als „Abschneiden in Richtung Null“ bezeichnet.
Nach dieser Regel -111 / 11
kann nur sein -10
nicht 1. Da (a/b)*b + a%b
muss gleich sein a
wir haben -111 % 11
ist -1
.
K&R Kapitel 2.5 gibt jedoch eine andere Antwort:
Die Richtung des Abschneidens bei / und das Vorzeichen des Ergebnisses bei % sind bei negativen Operanden maschinenabhängig, ebenso die Aktion bei Überlauf oder Unterlauf.
Demnach auch nicht -1
oder 10
kann ein rechtliches Ergebnis sein.
Der Grund liegt in C89 3.3.5:
Wenn ganze Zahlen dividiert werden und die Division ungenau ist und beide Operanden positiv sind, ist das Ergebnis des /-Operators die größte ganze Zahl kleiner als der algebraische Quotient und das Ergebnis des %-Operators ist positiv. Wenn einer der Operanden negativ ist, ist es implementierungsdefiniert, ob das Ergebnis des /-Operators die größte ganze Zahl kleiner als der algebraische Quotient oder die kleinste ganze Zahl größer als der algebraische Quotient ist, ebenso wie das Vorzeichen des Ergebnisses des %-Operators. Wenn der Quotient a/b darstellbar ist, soll der Ausdruck (a/b)*b + a%b gleich a sein.
Es stellt sich heraus, dass es sich um einen Wechsel von C89 zu C99 handelt.
C99 Begründung 6.5.5 liefert einige historische Gründe:
In C89 konnte die Division von ganzen Zahlen mit negativen Operanden auf eine implementierungsdefinierte Weise auf- oder abrunden; Die Absicht bestand darin, Overhead im Laufzeitcode zu vermeiden, um nach Sonderfällen zu suchen und bestimmtes Verhalten zu erzwingen. In Fortran wird das Ergebnis jedoch immer gegen Null abgeschnitten, und der Overhead scheint für die Gemeinschaft der numerischen Programmierer akzeptabel zu sein. Daher erfordert C99 jetzt ein ähnliches Verhalten, was die Portierung von Code von Fortran nach C erleichtern sollte. Die Tabelle in §7.20.6.2 dieses Dokuments veranschaulicht die erforderliche Semantik.
Und hier ist die Tabelle in §7.20.6.2:
numer denom quot rem
7 3 2 1
–7 3 –2 –1
7 –3 –2 1
–7 –3 2 –1
Für den Modulus wäre -1 eine falsche Antwort.
Cs %
operator ist jedoch ein Restoperator, kein Modulusoperator – und für Rest ist entweder 10 oder -1 zulässig.
Das %
Operator ist so implementiert, dass a == b * (a / b) + (a % b)
wahr ist, wobei wir eine ganzzahlige Division verwenden.
In diesem Fall -111 / 11
ist -10
Also -111 == 11 * -10 + x
ist damit zufrieden x == -1
.
Ah, der alte negative Operandenmodul 🙂 Ich erinnere mich, dass Python es in allen Spezialfällen richtig gemacht hat (im mathematischen Sinne).
– Kamerun
4. Juli 2013 um 3:46 Uhr
Wenn Sie den ‘%’-Operator von C in einen Modulus zwingen möchten, der so funktioniert, wie Sie es erwartet haben, tun Sie einfach Folgendes:
((a % b) + b) % b
– Reisfeld
4. Juli 2013 um 4:01 Uhr
Es gibt eine sehr schöne Tabelle auf der Wikipedia-Seite von Modulo Operation, die zeigt, wie jede Sprache ihre eigene Modulo-Implementierung hat: en.wikipedia.org/wiki/Modulo_operation
– Daan Timmer
4. Juli 2013 um 7:14 Uhr
Ein hilfreicher Beitrag für Sie, wie Sie einen Modulo-Operator (%) in C/C++/Obj-C codieren, der negative Zahlen verarbeitet
– Grijesh Chauhan
4. Juli 2013 um 7:33 Uhr
Die Antwort von Yu Hao sollte meiner Meinung nach als Antwort markiert werden, aber es ist erwähnenswert, dass andere Sprachen dies möglicherweise anders machen. Ada hat zwei getrennte Funktionen: eine Restfunktion und eine Modulo-Funktion. Python behandelt auch negative Zahlen anders, wenn es seinen Modulo-Operator verwendet.
– Benutzer539810
4. Juli 2013 um 8:42 Uhr