2012-07-30 16 views
115

In einem C-Programm war ich die folgenden Operationen versuchen (Gerade das Verhalten zu überprüfen)Modulo Betrieb mit negativen Zahlen

x = 5 % (-3); 
y = (-5) % (3); 
z = (-5) % (-3); 

printf("%d ,%d ,%d", x, y, z); 

gab mir Ausgabe als (2, -2 , -2) in gcc. Ich habe jedes Mal ein positives Ergebnis erwartet. Kann ein Modul negativ sein? Kann jemand dieses Verhalten erklären?

+0

Mögliches Duplikat von http://stackoverflow.com/questions/4003232/how-to-code-a-modulo-operator-in-cc-obj-c-that-handles-negative-numbers – james

+1

mögliche Duplikate von [ Modulo-Operator mit negativen Werten] (http://stackoverflow.com/questions/7594508/modulo-operator-with-negative-values) – sugavaneshb

Antwort

3

Das Ergebnis der Modulo-Operation auf dem Vorzeichen des Zählers abhängt, und somit sind Sie immer -2 für y und z

Hier ist die Referenz

http://www.chemie.fu-berlin.de/chemnet/use/info/libc/libc_14.html

Integer Division

Dieser Abschnitt beschreibt Funktionen zur Durchführung von Integer-Divisionen. Diese Funktionen sind in der GNU C-Bibliothek redundant, da in GNU C der Operator '/' immer auf Null aufrundet. In anderen C Implementierungen kann '/' jedoch anders mit negativen Argumenten runden. div und ldiv sind nützlich, weil sie angeben, wie der Quotient abgerundet wird: gegen Null. Der Rest hat das gleiche Vorzeichen wie der Zähler .

+4

Sie beziehen sich auf einen Text über ANSI C. Dies ist eine ziemlich alte Norm von C. Nicht Sicher, ob der Text in Bezug auf ANSI C korrekt ist, aber definitiv nicht in Bezug auf C99. In C99 §6.5.5 ist die Integer-Division so definiert, dass sie immer in Richtung Null abgeschnitten wird. – Palec

+0

und ein Link: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf –

102

C99 erfordert, dass, wenn a/b darstellbare ist:

(a/b) * b+a%b wird a

gleich Dies macht Sinn, logisch. Richtig?

Mal sehen, was dies führt zu:


Beispiel A. 5/(-3)-1

=> ist (-1) * (-3)+5%(-3) = 5

Dies geschieht nur, wenn 5%(-3) ist 2.


Beispiel B.(-5)/3 ist -1

=>(-1) * 3+(-5)%3 = -5

Dies kann nur geschehen, wenn (-5)%3-2

+1

Sollte der Compiler intelligent genug sein und erkennen, dass ein unsignierter Modulo ein anderer unsignierter immer positiv ist? Zur Zeit (naja, GCC 5.2) scheint der Compiler zu denken, dass "%" in diesem Fall ein "int" anstatt "unsigned" zurückgibt, selbst wenn beide Operanden uint32_t oder größer sind. –

+0

@FrederickNord Haben Sie ein Beispiel für [dieses Verhalten] (http://stackoverflow.com/questions/11720656/modulo-operation-with-negative-numbers#comment66655578_11720841)? – chux

85

Der % Operator in C ist nicht der Modulo Operator ist aber der Rest Operator.

Modulo und Restoperatoren unterscheiden sich in Bezug auf negative Werte.

Bei einem Restoperator entspricht das Vorzeichen des Ergebnisses dem Vorzeichen des Dividenden, während bei einem Modulooperator das Vorzeichen des Ergebnisses dem Divisor entspricht.

C definiert die % Operation für a % b als:

a == (a/b * b) + a % b 

/ mit der Ganzzahl-Division mit Trunkierung Richtung 0. Das ist die Abschneidung, die in Richtung 0 (und nicht in Richtung negativer Inunität) ausgeführt wird, die % als Restoperator und nicht als Modulooperator definiert.

+4

[Rest ist das Ergebnis der Modulo-Operation] (https://en.wikipedia.org/wiki/Remainder) per Definition. Es sollte keinen Restoperator geben, da es keine Restoperation gibt, sondern Modulo. – gronostaj

+21

@gronostaj nicht in CS. Schauen Sie sich höhere Sprachen wie Haskell oder Scheme an, die beide zwei verschiedene Operatoren definieren ("Rest" und "Modulo" in Scheme, "Rem" und "Mod" in Haskell). Diese Operatorenspezifikationen unterscheiden sich in diesen Sprachen davon, wie die Division ausgeführt wird: Abschneiden in Richtung 0 oder in Richtung negatives Unendlich. Übrigens nennt der C-Standard niemals den '%' den * Modulo-Operator *, sondern nur den *% -Operator *. – ouah

+0

Nicht zu verwechseln mit der 'Rest'-Funktion in C, die den IEEE-Rest mit der runden-nächsten-Semantik in der Division – Eric

44

Basierend auf der C99 Spezifikation: a = (a/b) * b + a % b

wir eine Funktion (a % b) = a - (a/b) * b berechnen schreiben kann!

int remainder(int a, int b) 
{ 
    return a - (a/b) * b; 
} 

Für Modulo-Operation können wir die folgende Funktion (unter der Annahme, b> 0) haben

int mod(int a, int b) 
{ 
    int r = a % b; 
    return r < 0 ? r + b : r; 
} 

Meine Schlussfolgerung ist, (a% b) in C ein Rest-Operator ist und NOT-Operator Modulo.

+1

implementiert. Dies ergibt keine positiven Ergebnisse, wenn 'b' negativ ist (und tatsächlich für 'r' und "b" beide negativ ergeben Ergebnisse kleiner als "-b". Um positive Ergebnisse für alle Eingaben zu erzielen, können Sie 'r + abs (b)' verwenden oder, um 'b's Zeichen anzupassen, können Sie stattdessen die Bedingung in' r * b <0' ändern. –

4

Die anderen Antworten werden in C99 oder später Division von ganzen Zahlen beteiligen negative Operanden erklären immer gestutzt gegen Null.

Beachten Sie, dass in C89, ob die Ergebnis-Runde nach oben oder unten ist Implementierung definiert. Da (a/b) * b + a%b in allen Standards gleich a ist, ist das Ergebnis von % mit negativen Operanden ebenfalls in C89 implementierungsdefiniert.

23

Ich glaube nicht, dass es notwendig ist zu überprüfen, ob die Zahl negativ ist. Die einfachste allgemeine Funktion, um das positive Modulo zu finden, wäre dies - Es würde sowohl bei positiven als auch negativen Werten von x funktionieren.

+0

Das hat für mich funktioniert. Danke!!! –

3

In der Mathematik, woher diese Konventionen stammen, gibt es keine Behauptung, dass die Modulo-Arithmetik ein positives Ergebnis liefern sollte.

Eg.

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)

Ähnlich, -1 mod 5 = -1, aber es kann auch gleich 4. Das ist, - 1/5 ergibt einen Rest -1 von 0 oder 4 von -5. (Beide Faktoren von 5)

Für weitere Informationen in equivalence classes in Mathematik.

0

Der Modulo-Operator ist wie der Mod-Operator, wenn die Zahl positiv ist, aber unterschiedlich, wenn die Zahl negativ ist.

Viele Male in den Problemen werden wir gebeten, die Antwort modulo 10^9 + 7 zu geben.

Lassen Sie die Antwort (vor der Verwendung von Modulo) mit "a" gekennzeichnet werden.

einfacher direkt Rule-

wenn ein positives ist, dann ist ein modulo 10^9 + 7 = a% (10^9 + 7)

wenn ein negativ ist, dann ein Modulo-10^9 + 7 = (a% (10^9 + 7)) + (10^9 + 7)

Wenn in suc h Probleme, wir finden, dass jeder Schritt der Schleife einen Wert berechnen kann, der außerhalb des ganzzahligen Bereichs liegt (wenn wir Ganzzahlen verwenden), dann können wir den Modulo-Operator in diesem Schritt selbst verwenden. Die endgültige Antwort lautet so, als hätten wir den Modulo-Operator nur einmal benutzt.

Dies ist, weil- (a * b)% c = ((a% c) (b% c))% c Das gleiche gilt für Addition und Subtraktion.

1

Modulus-Operator gibt den Rest. Modulo-Operator in c nimmt normalerweise das Vorzeichen des Zählers

  1. x = 5% (-3) - hier Zähler positiv ist daher resultiert dies in 2
  2. y = (-5)% (3) - hier ist somit negativ Zähler ergibt es -2
  3. z = (-5)% (-3) - hier Zähler negativ ist daher ergibt sich, -2

auch Modul (Rest) Operator kann nur verwendet werden, mit Integer-Typ und kann nicht mit Fließkomma verwendet werden.

+0

Es wäre nett, wenn Sie dies mit Links zu externen Ressourcen sichern können. –

+0

https://archive.org/details/letusc_201605 – Kavya