it-swarm.com.de

Modulo-Betrieb mit negativen Zahlen

In einem C-Programm habe ich die folgenden Operationen ausprobiert (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 die 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?

151
Alva

C99 erfordert dass, wenn a/b darstellbar ist:

(a/b) * b+a%b soll a sein

Das macht logisch Sinn. Recht?

Mal sehen, wozu das führt:


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

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

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


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

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

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

132
ArjunShankar

Der %-Operator in C ist nicht der modulo - Operator, sondern der rest - Operator.

Modulo- und Restoperatoren unterscheiden sich in Bezug auf negative 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ür a % b als:

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

mit / die ganzzahlige Division mit Kürzung in Richtung 0. Das ist die Kürzung, die in Richtung auf 0 erfolgt (und nicht in Richtung auf negative Inifinity), die den % als Restoperator und nicht als Modulooperator definiert.

111
ouah

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

Wir können eine Funktion schreiben, um (a % b) = a - (a / b) * b zu berechnen!

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

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

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

Meine Schlussfolgerung ist (a% b) in C ist ein Restoperator und NICHT Modulo-Operator.

56
dewang

Ich denke nicht, dass es keine Notwendigkeit gibt zu prüfen, ob die Zahl negativ ist.

Eine einfache Funktion, um das positive Modulo zu finden, wäre dies -

int modulo(int x,int N){
    return (x % N + N) %N;
}

Angenommen, N ist positiv, funktioniert dies für sowohl positive als auch negative Werte von x.

P.S. auch, wie von @chux ausgeführt, Wenn Ihr x und N etwas wie INT_MAX-1 bzw. INT_MAX erreichen können, ersetzen Sie einfach int durch long long int.

Und wenn sie auch lange Grenzen überschreiten (d. H. In der Nähe von LLONG_MAX), müssen Sie positive und negative Fälle getrennt behandeln, wie in den anderen Antworten beschrieben.

39

Die anderen Antworten haben in C99 oder später die Aufteilung von Ganzzahlen mit negativen Operanden erklärt, die immer auf Null abschneiden

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

7
Yu Hao

Kann ein Modul negativ sein? 

% ist der rest-Operator , der Rest nach der Division, nicht nach Euclidean_division . Seit C99 kann das Ergebnis 0, negativ oder positiv sein.

 // a % b
 7 %  3 -->  1  
 7 % -3 -->  1  
-7 %  3 --> -1  
-7 % -3 --> -1  

Ich habe jedes Mal ein positives Ergebnis erwartet.

Um ein euklidisches Modulo durchzuführen, das immer definiert ist, wenn a/b definiert ist, sind a,b Vorzeichen und das Ergebnis ist niemals negativ:

int modulo_Euclidean(int a, int b) {
  int m = a % b;
  if (m < 0) {
    // m += (b < 0) ? -b : b; // avoid this form: it is UB when b == INT_MIN
    m = (b < 0) ? m - b : m + b;
  }
  return m;
}

modulo_Euclidean( 7,  3) -->  1  
modulo_Euclidean( 7, -3) -->  1  
modulo_Euclidean(-7,  3) -->  2  
modulo_Euclidean(-7, -3) -->  2   
3
chux

Das Ergebnis der Modulo-Operation hängt vom Vorzeichen des Zählers ab, und Sie erhalten -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

In diesem Abschnitt werden Funktionen zum Durchführen einer Ganzzahldivision beschrieben. Diese Funktionen sind in der GNU C-Bibliothek redundant, da in GNU C der '/' Operator rundet immer gegen Null. Aber in anderen C Implementierungen, '/' kann mit negativen Argumenten anders gerundet werden . div und ldiv sind nützlich, weil sie angeben, wie die .__ gerundet werden soll. Quotient: gegen null. Der Rest hat dasselbe Zeichen wie der Zähler.

3
Kartik Anand

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 gilt: - 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 Äquivalenzklassen in Mathematik. 

2
DarkPurple141

Gemäß C99-Standard , Abschnitt 6.5.5 Multiplikative Operatoren ist Folgendes erforderlich:

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

Fazit

Das Vorzeichen des Ergebnisses einer Restoperation nach C99 ist das gleiche wie das der Dividende.

Sehen wir uns einige Beispiele an (dividend / divisor):

Wenn nur die Dividende negativ ist

(-3 / 2) * 2  +  -3 % 2 = -3

(-3 / 2) * 2 = -2

(-3 % 2) must be -1

Wenn nur der Divisor negativ ist

(3 / -2) * -2  +  3 % -2 = 3

(3 / -2) * -2 = 2

(3 % -2) must be 1

Wenn sowohl Divisor als auch Dividende negativ sind

(-3 / -2) * -2  +  -3 % -2 = -3

(-3 / -2) * -2 = -2

(-3 % -2) must be -1

6.5.5 Multiplikationsoperatoren

Syntax

  1. multiplikativer Ausdruck:
    • cast-expression
    • multiplicative-expression * cast-expression
    • multiplicative-expression / cast-expression
    • multiplicative-expression % cast-expression

Einschränkungen

  1. Jeder der Operanden muss einen arithmetischen Typ haben. Das Operanden des Operators % müssen vom Typ Integer sein.

Semantik

  1. Die üblichen arithmetischen Konvertierungen werden an der .__ durchgeführt. Operanden.

  2. Das Ergebnis des binären * - Operators ist das Produkt von die Operanden.

  3. Das Ergebnis des Operators / ist der Quotient aus die Division des ersten Operanden durch den zweiten; das Ergebnis des % - Operators ist der Rest. Sowohl Operationen, wenn der Wert des zweiten Operanden Null ist, das Verhalten ist undefiniert.

  4. Wenn Ganzzahlen geteilt werden, wird das Ergebnis des / - Operators ist der algebraische Quotient mit einem Bruchteil verworfen [1]. Wenn der Quotient a/b darstellbar ist, der Ausdruck (a/b)*b + a%b soll a sein.

[1]: Dies wird oft als "Abschneiden gegen Null" bezeichnet.

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

  1. x = 5% (-3) - hier ist der Zähler positiv, daher ergibt sich 2
  2. y = (-5)% (3) - hier ist der Zähler negativ, also ergibt sich -2
  3. z = (-5)% (-3) - hier ist der Zähler negativ, also ergibt sich -2

Der Modulus (rest) -Operator kann nur mit dem Ganzzahlentyp und nicht mit Fließkommazahl verwendet werden.

1
Kavya

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

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

Die Antwort (vor der Verwendung von Modulo) sei mit 'a' bezeichnet.

Einfache unkomplizierte Regel-

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

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

Wenn wir bei solchen Problemen feststellen, dass jeder Schritt der Schleife einen Wert außerhalb des ganzzahligen Bereichs berechnen kann (wenn wir Ganzzahlen verwenden), können wir den modulo-Operator in diesem Schritt selbst verwenden. Die endgültige Antwort ist, als hätten wir den Modulo-Operator nur einmal verwendet.

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

0
Akash Bhalotia

Ich glaube, es ist sinnvoller, an mod zu denken, wie es in der abstrakten Arithmetik definiert ist. nicht als Operation, sondern als ganz andere Klasse von Arithmetik, mit verschiedenen Elementen und verschiedenen Operatoren. Dies bedeutet, dass die Addition in mod 3 nicht mit der "normalen" Addition identisch ist. das ist; ganzzahlige Addition.

Also wenn du das tust:

5 % -3

Sie versuchen, die Ganzzahl 5 einem Element in der Menge von mod -3 zuzuordnen. Dies sind die Elemente von mod -3:

{ 0, -2, -1 }

So:

0 => 0, 1 => -2, 2 => -1, 3 => 0, 4 => -2, 5 => -1

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 Sinn macht, Negative zurückzugeben.

0
FelipeC