In einem C-Programm habe ich die folgenden Operationen versucht (nur um das Verhalten zu überprüfen)
x = 5 % (-3);
y = (-5) % (3);
z = (-5) % (-3);
printf("%d ,%d ,%d", x, y, z);
gab mir Ausgabe wie (2, -2 , -2)
in gcc. Ich hatte jedes Mal ein positives Ergebnis erwartet. Kann ein Modul negativ sein? Kann jemand dieses Verhalten erklären?
Antworten:
C99 erfordert, dass wann darstellbar
a/b
ist:(a/b) * b
+a%b
soll gleich seina
Dies ist logischerweise sinnvoll. Richtig?
Mal sehen, wozu das führt:
Beispiel A.
5/(-3)
ist-1
=>
(-1) * (-3)
+5%(-3)
=5
Dies kann nur passieren, wenn
5%(-3)
2 ist.Beispiel B.
(-5)/3
ist-1
=>
(-1) * 3
+(-5)%3
=-5
Dies kann nur passieren, wenn dies der Fall
(-5)%3
ist-2
quelle
-5/3
ist-2
und der Mod wird 1. Kurz gesagt: Ein Modul hat ein Vorzeichen, das dem Dividendenzeichen folgt (abgeschnitten), das andere Modul hat ein Vorzeichen, das dem Divisorzeichen (Knuth) folgt.Der
%
Operator in C ist nicht der Modulo- Operator, sondern der Restoperator .Modulo- und Restoperatoren unterscheiden sich hinsichtlich negativer Werte.
Bei einem Restoperator entspricht das Vorzeichen des Ergebnisses dem Vorzeichen der Dividende, während bei einem Modulo-Operator das Vorzeichen des Ergebnisses dem Divisor entspricht.
C definiert die
%
Operation füra % b
:mit
/
der ganzzahligen Division mit Kürzung in Richtung0
. Dies ist die Kürzung, die in Richtung0
(und nicht in Richtung negativer Unendlichkeit) vorgenommen wird und die den%
Operator als Restoperator und nicht als Modulooperator definiert .quelle
remainder
undmodulo
in Schemerem
undmod
in Haskell). Diese Operatorspezifikationen unterscheiden sich in diesen Sprachen hinsichtlich der Art und Weise, wie die Division durchgeführt wird: Abschneiden gegen 0 oder gegen negative Unendlichkeit. Übrigens nennt der C-Standard niemals%
den Modulo-Operator , sondern nennt ihn nur den % -Operator .remainder
Funktion in C, die den IEEE-Rest mit einer auf die nächste Runde hin nächsten Semantik in der Division implementiertBasierend auf der C99-Spezifikation:
a == (a / b) * b + a % b
Wir können eine zu berechnende Funktion schreiben
(a % b) == a - (a / b) * b
!Für den Modulo-Betrieb können wir die folgende Funktion haben (vorausgesetzt
b > 0
)Mein Fazit ist, dass
a % b
in C eine Restoperation und KEINE Modulooperation ist.quelle
b
negativ ist (und in der Tat fürr
undb
sowohl negative als es gibt die Ergebnisse weniger als-b
). Um positive Ergebnisse für alle Eingaben zu gewährleisten, die Sie verwenden können,r + abs(b)
oder um mit demb
Vorzeichen übereinzustimmen, können Sier*b < 0
stattdessen die Bedingung in ändern .r + abs(b)
ist UB wennb == INT_MIN
.Ich glaube nicht, dass überprüft werden muss, ob die Zahl negativ ist.
Eine einfache Funktion, um das positive Modulo zu finden, wäre dies -
Edit: Angenommen
N > 0
undN + N - 1 <= INT_MAX
Dies funktioniert sowohl für positive als auch für negative Werte von x.
Original PS: auch Wie von @chux, Wenn x und N können so etwas wie INT_MAX-1 erreichen und INT_MAX jeweils nur ersetzen
int
mitlong long int
.Und wenn sie auch lange lange Grenzen überschreiten (dh in der Nähe von LLONG_MAX), müssen Sie positive und negative Fälle getrennt behandeln, wie in anderen Antworten hier beschrieben.
quelle
N < 0
das Ergebnis wie in negativ sein kannmodulo(7, -3) --> -2
. Auchx % N + N
kann überlaufenint
Mathe , das Verhalten ist nicht definiert. zBmodulo(INT_MAX - 1,INT_MAX)
könnte -3 ergeben.long long int
den negativen Fall einfach verwenden oder separat behandeln (auf Kosten des Verlusts der Einfachheit).Die anderen Antworten haben in C99 oder später erklärt, dass die Division von ganzen Zahlen mit negativen Operanden immer gegen Null abschneidet .
Beachten Sie, dass in C89 die Implementierungsdefinition festgelegt ist, ob das Ergebnis nach oben oder unten gerundet wird. Denn
(a/b) * b + a%b
gleicha
in allen Standards, das Ergebnis%
ist negativ Operanden beteiligt auch die Implementierung definiert in C89.quelle
%
kann negativ sein, da es sich um den Restoperator handelt , den Rest nach der Division, nicht nach Euclidean_division . Seit C99 kann das Ergebnis 0 sein, negativ oder positiv.Das gewünschte Modulo OP ist ein klassisches euklidisches Modulo , nicht
%
.Um ein euklidisches Modulo auszuführen, das immer dann gut definiert
a/b
ist, wenn es definiert ist, hata,b
es ein beliebiges Vorzeichen und das Ergebnis ist niemals negativ:quelle
Das Ergebnis der Modulo-Operation hängt vom Vorzeichen des Zählers ab, und daher erhalten Sie -2 für y und z
Hier ist die Referenz
http://www.chemie.fu-berlin.de/chemnet/use/info/libc/libc_14.html
quelle
In der Mathematik, aus der diese Konventionen stammen, gibt es keine Behauptung, dass die Modulo-Arithmetik ein positives Ergebnis liefern sollte.
Z.B.
1 mod 5 = 1, kann aber auch gleich -4 sein. Das heißt, 1/5 ergibt einen Rest 1 von 0 oder -4 von 5. (Beide Faktoren von 5)
In ähnlicher Weise ist -1 mod 5 = -1, aber es kann auch gleich 4 sein. Das heißt, -1/5 ergibt einen Rest -1 von 0 oder 4 von -5. (Beide Faktoren von 5)
Weitere Informationen finden Sie in den Äquivalenzklassen in Mathematik.
quelle
a
undb
,b <> 0
. Nach dem euklidischen Divisionssatz existiert genau ein Paar von ganzen Zahlenm
,r
wobeia = m * b + r
und0 <= r < abs( b )
. Das Gesagter
ist das Ergebnis der (mathematischen) Modulo-Operation und per Definition nicht negativ. Weitere Informationen und Links auf Wikipedia: en.wikipedia.org/wiki/Euclidean_division1 mod 5
ist immer 1.-4 mod 5
könnte auch 1 sein, aber es sind verschiedene Dinge.Gemäß dem C99-Standard , Abschnitt 6.5.5 Multiplikative Operatoren , ist Folgendes erforderlich:
Fazit
Das Vorzeichen des Ergebnisses einer Restoperation gemäß C99 ist das gleiche wie das der Dividende.
Schauen wir uns einige Beispiele an (
dividend / divisor
):Wenn nur die Dividende negativ ist
Wenn nur der Divisor negativ ist
Wenn sowohl Divisor als auch Dividende negativ sind
quelle
Der Moduloperator gibt den Rest an. Der Moduloperator in c nimmt normalerweise das Vorzeichen des Zählers an
Auch der Moduloperator (Restoperator) kann nur mit einem ganzzahligen Typ und nicht mit einem Gleitkomma verwendet werden.
quelle
Ich glaube, es ist nützlicher, daran zu denken,
mod
wie es in der abstrakten Arithmetik definiert ist. nicht als Operation, sondern als eine ganz andere Klasse von Arithmetik mit verschiedenen Elementen und verschiedenen Operatoren. Das bedeutet, dass die Addition inmod 3
nicht mit der "normalen" Addition identisch ist. das ist; Ganzzahladdition.Also, wenn Sie tun:
Sie versuchen, die Ganzzahl 5 einem Element in der Menge von zuzuordnen
mod -3
. Dies sind die Elemente vonmod -3
:So:
Angenommen, Sie müssen aus irgendeinem Grund 30 Stunden aufbleiben. Wie viele Stunden haben Sie noch an diesem Tag?
30 mod -24
.Aber was C implementiert, ist nicht
mod
, es ist ein Rest. Der Punkt ist jedenfalls, dass es sinnvoll ist, Negative zurückzugeben.quelle