Was sind die Regeln für modulare Arithmetik in C?

Lesezeit: 6 Minuten

Benutzer-Avatar
Theo Chronik

In früheren Kursen wurde mir das beigebracht n % d = r und darüber nachzudenken als n = d*q + rwo 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 10Weil -111 = -11*-11 + 10 (im Gegensatz zu -111 = -11*10 -1da 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?

  • 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


Benutzer-Avatar
Yu Hao

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 -10nicht 1. Da (a/b)*b + a%b muss gleich sein awir 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

  • Ich denke, nur -1 ist zulässig – Fußnote 90 (in Version n1256 des C99-Standards) sagt in Bezug auf den Text “[…] der algebraische Quotient mit jedem verworfenen Bruchteil”, dass “dies oft als Abschneiden in Richtung 0 bezeichnet wird”. Also verstehe ich das so -111 / 11 kann nur -10 sein, und daher -111 % 11 kann aufgrund der Anforderung nur -1 sein (a/b)*b + a%b muss gleich sein a.

    – Adam Rosenfield

    4. Juli 2013 um 4:04 Uhr

  • Außerdem funktionieren bitweise Operatoren anders! Wenngleich & und >> werden normalerweise mit Modulo und Division in Potenzen von 2 verglichen, >> nicht “in Richtung Null abschneiden”, also -5 >> 1 == -3und -11 & 3 == 1 (während -11 % 4 == -3)

    – i Code 4 Essen

    4. Juli 2013 um 4:26 Uhr


  • Ja, das wurde in C99 geändert. C89-Compiler können beides und tun im Allgemeinen, was für die Hardware am bequemsten ist.

    – Torek

    4. Juli 2013 um 4:51 Uhr

  • @iCode4Food Rechtsverschiebung von int ist implementierungsdefiniert.

    – Jim Balter

    4. Juli 2013 um 6:21 Uhr

Benutzer-Avatar
Jerry Sarg

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.

  • Bitte definieren Sie, was Sie mit Modul meinen. Je nach Kontext scheint es unterschiedliche Definitionen zu geben, und für einige davon wäre ISTM, dass -1 richtig wäre.

    – Rudy Velthuis

    8. Juni 2014 um 18:03 Uhr

  • @RudyVelthuis: “Modulus” wird normalerweise mit assoziiert Modulararithmetik. Zumindest als modulare Arithmetik normalerweise definiert ist, sind nur nicht negative Zahlen erlaubt.

    – Jerry Sarg

    8. Juni 2014 um 18:10 Uhr

  • Wie gesagt, es kommt auf den Kontext an. Wenn Sie auf eine euklidische Teilung hinweisen, dann ist der Rest tatsächlich immer positiv. Aber in anderen Kontexten ist dies nicht unbedingt der Fall. Zumal dies ein Programmierforum ist, sollte bekannt sein, dass die Bedeutung von „Modulus“ von Sprache zu Sprache unterschiedlich sein kann.

    – Rudy Velthuis

    8. Juni 2014 um 21:10 Uhr

  • @RudyVelthuis: Ich bin anderer Meinung. Modul bedeutet, was es bedeutet. Die meisten Sprachen implementieren etwas, das unter bestimmten Umständen ähnlich sein kann, sich aber (in den meisten Fällen) unter anderen unterscheiden wird.

    – Jerry Sarg

    8. Juni 2014 um 22:40 Uhr

  • Können Sie dann eine verbindliche Definition des Moduls geben? ISTM, dass Modul in verschiedenen Kontexten unterschiedliche Dinge bedeutet.

    – Rudy Velthuis

    9. Juni 2014 um 8:37 Uhr

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 -10Also -111 == 11 * -10 + x ist damit zufrieden x == -1.

  • IOW, a % b = a - (a / b) * b. Seit -111 / 11 ergibt sich -10Das Ergebnis ist -111 - (-10 * 11)dh -1.

    – Rudy Velthuis

    8. Juni 2014 um 18:08 Uhr

1298880cookie-checkWas sind die Regeln für modulare Arithmetik in C?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy