Wie führt Java Modulberechnungen mit negativen Zahlen durch?


91

Mache ich den Modul falsch? Da in Java -13 % 64sollte bewerten , -13aber ich erhalte 51.


102
@ Dan Auch ohne statische Hauptlücke ... Ich sehe Code.
Joris Meys

22
Ich bekomme -13 & 64 == -13
Grodriguez

7
Wie kommt es, dass Sie 51 Stunden als -13 bekommen?
Raedwald

3
Sie machen überhaupt keinen Modul. In Java gibt es keinen Modulo-Operator. %ist ein Restoperator.
Marquis von Lorne

3
Verwirrende Frage: Java 8 gibt -13, wie einige andere Leute sagen. Mit welcher Java-Version haben Sie das angeblich bekommen?
Jan Żankowski

Antworten:


102

Beide Definitionen des Moduls negativer Zahlen werden verwendet - einige Sprachen verwenden eine Definition und andere die andere.

Wenn Sie eine negative Zahl für negative Eingänge erhalten möchten, können Sie Folgendes verwenden:

int r = x % n;
if (r > 0 && x < 0)
{
    r -= n;
}

Ebenso, wenn Sie eine Sprache verwenden, die bei einer negativen Eingabe eine negative Zahl zurückgibt, und Sie eine positive bevorzugen würden:

int r = x % n;
if (r < 0)
{
    r += n;
}

3
Dies funktioniert nicht gut, wenn n negativ ist. Wenn Sie dasselbe Beispiel aus Java 7 Lang Spec (Abschnitt 15.17.3) verwenden: (-5)% (-3) = -2. Das Hinzufügen von -3 funktioniert nicht. Sie sollten den absoluten Wert von n hinzufügen, wenn Sie sicher sein möchten, dass der Wert positiv ist.
Partlov

5
In Java ändert negatives Modulo nichts. Wenn Sie trotzdem Abs () verwenden, schreiben Sie einfach r = x% abs (n). Ich mag keine if-Anweisung, ich schreibe lieber r = ((x% n) + n)% n. Bezüglich der Potenz von 2 Modulo (2,4,8,16 usw.) und der positiven Antwort wird die binäre Maske r = x & 63
berücksichtigt

3
Im Kontext von Java (gemäß Frage-Tag) ist diese Antwort im Wesentlichen "falsch". Wenn der Ausdruck x % yA) gegeben ist, xist der Rest negativ, dh negativ x % y == -(-x % y). B) das Zeichen von yhat keine Wirkung, dhx % y == x % -y
Bohemian

70

Da "mathematisch" beide richtig sind:

-13 % 64 = -13 (on modulus 64)  
-13 % 64 = 51 (on modulus 64)

Eine der Optionen musste von Java-Sprachentwicklern ausgewählt werden und sie wählten:

Das Vorzeichen des Ergebnisses entspricht dem Vorzeichen der Dividende.

Sagt es in Java-Spezifikationen:

https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.17.3


8
Die Frage ist "Warum gibt mir Java, -13 % 64 = 51als ich erwartet hatte -13?".
Pascal Cuoq

5
@pascal: Java gibt Ihnen die richtige Definition in Mathematik und die Art und Weise, wie es implementiert wurde, um dies zu tun, nicht das, was Sie von ihm erwarten.

8
Das mathematisch vernünftige Verhalten ist in Java 8 verfügbar: Math.floorMod
Jesse Glick

1
Etwas in ihrem 15.17.3. Die restlichen Beispiele für Operator% sind nicht klar. int result = (-5) % 3;gibt -2. int result = (-3) % 5;gibt -3. Gibt im Allgemeinen int result = (-a) % b;die richtige Antwort, wenn | -a | > b. Um das richtige Ergebnis zu erhalten, wenn | -a | <b wir sollten den Divisor einwickeln. int result = ((-a) % b) + b;für negative a oder int result = (((-a) % b) + b) % b;für positive oder negative a
Oz Edri

@Caner Ich habe das nicht verstanden. Wie können beide gleich sein?
Kishore Kumar Korada

20

Sind Sie sicher, dass Sie in Java arbeiten? Weil Java wie erwartet -13% 64 = -13 ergibt. Das Zeichen der Dividende!


15

Ihr Ergebnis ist für Java falsch. Bitte geben Sie einen Kontext an, wie Sie dazu gekommen sind (Ihr Programm, Ihre Implementierung und Ihre Java-Version).

Von dem Java-Sprachspezifikation

15.17.3 Restbetreiber%
[...]
Die für Operanden, die nach der binären numerischen Heraufstufung Ganzzahlen sind (§5.6.2), erzeugt einen Ergebniswert, so dass (a / b) * b + (a% b) gleich ist ein.
15.17.2 Abteilungsbetreiber /
[...]
Integer Division rundet auf 0.

Da / gegen Null gerundet ist (was zu Null führt), sollte das Ergebnis von% in diesem Fall negativ sein.


Etwas in ihrem 15.17.3. Die restlichen Beispiele für Operator% sind nicht klar. int result = (-5) % 3;gibt -2 int result = (-3) % 5;gibt -3 Gibt im Allgemeinen int result = (-a) % b;die richtige Antwort, wenn | -a | > b Um das richtige Ergebnis zu erhalten, wenn | -a | <b wir sollten den Divisor einwickeln. int result = ((-a) % b) + b;für negativ a oder int result = (((-a) % b) + b) % b;für positiv oder negativ a.
Oz Edri

1
Ihr Kommentar ist ziemlich unklar. Der Abschnitt definiert das richtige Ergebnis, und die Beispiele stimmen mit dieser Definition überein. Für Ihr Beispiel ist (-3) % 5das richtige Ergebnis gemäß der Definition -3, und eine korrekte Implementierung von Java sollte dieses Ergebnis erzeugen.
Starblue

Ich habe mich wohl nicht richtig erklärt. Was ich mit "der richtigen Antwort" meinte, wenn | -a | <b ist, dass wir, um ein positives Ergebnis zu erhalten, das gegebene Ergebnis von a% b "einschließen" sollten, indem wir b hinzufügen. In meinem Beispiel gibt es (-3)%5tatsächlich -3, und wenn wir den positiven Rest wollen, sollten wir 5 hinzufügen, und dann wird das Ergebnis sein2
Oz Edri

5

Sie können verwenden

(x % n) - (x < 0 ? n : 0);

2
@ruslik Sie können auch tun : ((x % k) + k) % k. (Obwohl Ihre wahrscheinlich besser lesbar ist.)
John Kurlak

1
@JohnKurlak Ihre Version funktioniert folgendermaßen: 4% 3 = 1 ODER 4% -3 = -2 ODER -4% 3 = 2 ODER -4% -3 = -1, aber die von ruslik funktioniert folgendermaßen: 4% 3 = 1 ODER 4% -3 = 1 ODER -4% 3 = -4 ODER -4% -3 = 2
Joschua

@ Joschua Danke für den Hinweis. Mein Code ist hilfreich, wenn Sie möchten, dass das Modulergebnis im Bereich von [0, sign(divisor) * divisor)statt liegt [0, sign(dividend) * divisor).
John Kurlak

3

Ihre Antwort ist in Wikipedia: Modulo-Betrieb

Es heißt, dass in Java das Vorzeichen für die Modulo-Operation das gleiche ist wie das der Dividende. und da wir über den Rest der Divisionsoperation sprechen, ist es in Ordnung, dass sie in Ihrem Fall -13 zurückgibt, da -13/64 = 0. -13-0 = -13.

EDIT: Sorry, habe deine Frage falsch verstanden ... Du hast recht, Java sollte -13 geben. Können Sie mehr umgebenden Code bereitstellen?


2

Die Modulo-Arithmetik mit negativen Operanden wird vom Sprachdesigner definiert, der sie möglicherweise der Sprachimplementierung überlässt und die Definition möglicherweise auf die CPU-Architektur verschiebt.

Ich konnte keine Java-Sprachdefinition finden.
Dank Ishtar sagt die Java-Sprachspezifikation für den Restoperator% , dass das Vorzeichen des Ergebnisses mit dem Vorzeichen des Zählers übereinstimmt.


1

Um dies zu überwinden, können Sie 64den negativen Wert addieren (oder was auch immer Ihre Modulbasis ist), bis er positiv ist

int k = -13;
int modbase = 64;

while (k < 0) {
    k += modbase;
}

int result = k % modbase;

Das Ergebnis liegt weiterhin in derselben Äquivalenzklasse.


1

x = x + m = x - mim Modul m.
also -13 = -13 + 64im Modul 64 und -13 = 51im Modul 64.
Nehmen wir an Z = X * d + r, wenn wir 0 < r < Xdann in Division den Rest nennen. gibt den Rest von zurück .Z/Xr
Z % XZ/X


1

Die Mod-Funktion ist definiert als der Betrag, um den eine Zahl das größte ganzzahlige Vielfache des Divisors überschreitet, das nicht größer als diese Zahl ist. Also in deinem Fall von

-13 % 64

Das größte ganzzahlige Vielfache von 64, das -13 nicht überschreitet, ist -64. Wenn Sie nun -13 von -64 subtrahieren, entspricht dies 51-13 - (-64) = -13 + 64 = 51


0

In meiner Version von Java JDK 1.8.0_05 -13% 64 = -13

Sie könnten versuchen, -13- (int (-13/64)), mit anderen Worten, eine Division in eine ganze Zahl umzuwandeln, um den Bruchteil zu entfernen, und dann vom Zähler zu subtrahieren. Also sollte Zähler- (int (Zähler / Nenner)) das Richtige geben Rest & Zeichen



0

Gemäß Abschnitt 15.17.3 des JLS "erzeugt die Restoperation für Operanden, die nach der binären numerischen Heraufstufung ganze Zahlen sind, einen Ergebniswert, so dass (a / b) * b + (a% b) gleich a ist. Diese Identität gilt gerade in dem speziellen Fall, dass die Dividende die negative ganze Zahl von größtmöglicher Größe für ihren Typ ist und der Divisor -1 ist (der Rest ist 0). "

Hoffentlich hilft das.


-1

Ich glaube nicht, dass Java in diesem Fall 51 zurückgibt. Ich verwende Java 8 auf einem Mac und bekomme:

-13 % 64 = -13

Programm:

public class Test {
    public static void main(String[] args) {
        int i = -13;
        int j = 64;
        System.out.println(i % j);
    }
}

4
@XaverKapeller, nein! Viele Leute wiesen darauf hin, dass mathematisch gesehen -13 und 51 korrekt sind. In Java ist -13 die erwartete Antwort, und das habe ich auch bekommen, daher weiß ich nicht, wie der Einsender 51 bekommen hat, es ist ein Rätsel. Modendetails zum Kontext können helfen, diese Frage richtig zu beantworten.
Fabyen

@ Xaver Kapeller: Wie können 51 und -13 beide richtig sein? Java würde nur einen Wert zurückgeben ..
Ceprateek

@XaverKapeller Wie kann eine Antwort, die dokumentiert, was Java tatsächlich tut, möglicherweise falsch sein?
Marquis von Lorne

@EJP Ich denke, als ich dies vor 3 Jahren schrieb, war ich dumm genug, die mathematische Genauigkeit mehr zu schätzen als die einfache Realität, wie Java damit umgeht. Vielen Dank, dass Sie mich daran erinnert haben, meinen dummen Kommentar zu entfernen: D
Xaver Kapeller
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.