In che modo Java esegue i calcoli del modulo con numeri negativi?


92

Sto sbagliando il modulo? Perché in Java -13 % 64si suppone che valuti -13ma ottengo 51.


102
@ Dan Anche senza un vuoto principale statico ... vedo il codice.
Joris Meys

22
Ottengo -13 e 64 == -13
Grodriguez

7
Com'è che stai ottenendo 51 ratehr rispetto a -13.
Raedwald

3
Non stai affatto facendo il modulo. Non esiste un operatore modulo in Java. %è un operatore resto.
Marchese di Lorne

3
Domanda confusa: Java 8 dà -13, come dicono altre persone. Con quale versione di Java l'hai presumibilmente ottenuto?
Jan Żankowski

Risposte:


103

Entrambe le definizioni di modulo dei numeri negativi sono in uso: alcune lingue usano una definizione e altre l'altra.

Se vuoi ottenere un numero negativo per input negativi, puoi usare questo:

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

Allo stesso modo se stai usando una lingua che restituisce un numero negativo su un input negativo e preferiresti positivo:

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

3
Questo non funziona bene se n è negativo. Se utilizzi lo stesso esempio da Java 7 Lang Spec (Sezione 15.17.3): (-5)% (-3) = -2. L'aggiunta di -3 non funzionerà. È necessario aggiungere il valore assoluto di n se si desidera essere sicuri che il valore sia positivo.
partlov

6
In Java il modulo negativo non cambia nulla, se usi comunque Abs (), scrivi semplicemente r = x% abs (n). Non mi piace l'istruzione if, preferisco scrivere r = ((x% n) + n)% n. Per quanto riguarda la potenza di 2 moduli (2,4,8,16, ecc.) E la risposta positiva, considera la maschera binaria r = x & 63.
Fabyen

3
Nel contesto di Java (come da tag della domanda) questa risposta è essenzialmente "sbagliata". Data l'espressione x % y, A) se xè negativo il resto è negativo, cioè x % y == -(-x % y). B) il segno di ynon ha effetto, ad esempiox % y == x % -y
Bohemian

71

Poiché "matematicamente" entrambi sono corretti:

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

Una delle opzioni doveva essere scelta dagli sviluppatori di linguaggi Java e hanno scelto:

il segno del risultato è uguale al segno del dividendo.

Lo dice nelle specifiche Java:

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


8
La domanda è "perché Java mi dà -13 % 64 = 51quando me l'aspettavo -13?".
Pascal Cuoq

5
@pascal: java ti dà la giusta definizione in matematica e il modo in cui è stato implementato per farlo non è quello che ti aspetti da esso.

9
Il comportamento matematicamente sano è disponibile in Java 8: Math.floorMod
Jesse Glick

1
Qualcosa nella loro 15.17.3. Gli esempi dell'operatore rimanente% non sono chiari. int result = (-5) % 3;dà -2. int result = (-3) % 5;dà -3. In generale, int result = (-a) % b;dà la risposta giusta quando | -a | > b. Per ottenere il risultato corretto quando | -a | <b dovremmo racchiudere il divisore. int result = ((-a) % b) + b;per a negativa o int result = (((-a) % b) + b) % b;per a positiva o negativa
Oz Edri

@ Caner non l'ho capito, come potrebbero essere entrambi uguali?
Kishore Kumar Korada

20

Sei sicuro di lavorare in Java? perché Java fornisce -13% 64 = -13 come previsto. Il segno del dividendo!


15

Il tuo risultato è sbagliato per Java. Fornisci un contesto su come ci sei arrivato (programma, implementazione e versione di Java).

Dal specifiche del linguaggio Java

15.17.3 Operatore rimanente%
[...]
L'operazione resto per operandi che sono numeri interi dopo la promozione numerica binaria (§5.6.2) produce un valore risultato tale che (a / b) * b + (a% b) è uguale a un.
15.17.2 Operatore Divisione /
[...]
divisione arrotonda verso 0.

Poiché / è arrotondato verso zero (risultando in zero), il risultato di% dovrebbe essere negativo in questo caso.


Qualcosa nella loro 15.17.3. Gli esempi dell'operatore rimanente% non sono chiari. int result = (-5) % 3;dà -2 int result = (-3) % 5;dà -3 In generale, int result = (-a) % b;dà la risposta giusta quando | -a | > b Per ottenere il risultato corretto quando | -a | <b dovremmo racchiudere il divisore. int result = ((-a) % b) + b;per a negativo o int result = (((-a) % b) + b) % b;per positivo o negativo a.
Oz Edri

1
Il tuo commento non è abbastanza chiaro. La sezione definisce il risultato corretto e gli esempi concordano con tale definizione. Per il tuo esempio, (-3) % 5il risultato corretto secondo la definizione è -3, e una corretta implementazione di Java dovrebbe produrre quel risultato.
starblue

Immagino di non essermi spiegato correttamente. Quello che intendevo per "la risposta giusta" quando | -a | <b è che per ottenere un risultato positivo dovremmo "racchiudere" il risultato dato da a% b aggiungendo b ad esso. Nel mio esempio, (-3)%5infatti dà -3, e se vogliamo il resto positivo dovremmo aggiungere 5 ad esso, e quindi il risultato sarà2
Oz Edri

6

Puoi usare

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

3
@ruslik È anche possibile fare: ((x % k) + k) % k. (Anche se il tuo è probabilmente più leggibile.)
John Kurlak

2
@JohnKurlak La tua versione funziona così: 4% 3 = 1 OR 4% -3 = -2 OR -4% 3 = 2 OR -4% -3 = -1 ma quella di ruslik funziona così: 4% 3 = 1 OR 4% -3 = 1 OR -4% 3 = -4 OR -4% -3 = 2
Joschua

1
@ Joschua Grazie per averlo sottolineato. Il mio codice è utile quando si desidera che il risultato del modulo sia compreso nell'intervallo [0, sign(divisor) * divisor)anziché [0, sign(dividend) * divisor).
John Kurlak,

3

La tua risposta è in wikipedia: operazione modulo

Dice che in Java il segno sull'operazione modulo è lo stesso di quello del dividendo. e poiché stiamo parlando del resto dell'operazione di divisione va benissimo, che nel tuo caso ritorni -13, poiché -13/64 = 0. -13-0 = -13.

EDIT: Scusa, ho capito male la tua domanda ... Hai ragione, java dovrebbe dare -13. Potete fornire più codice circostante?


2

L'aritmetica del modulo con operandi negativi è definita dal progettista del linguaggio, che potrebbe lasciarla all'implementazione del linguaggio, che potrebbe rimandare la definizione all'architettura della CPU.

Non sono riuscito a trovare una definizione del linguaggio Java.
Grazie Ishtar, Java Language Specification for the Remainder Operator% afferma che il segno del risultato è lo stesso del segno del numeratore.


1

Per ovviare a questo, potresti aggiungere 64(o qualunque sia la tua base di modulo) al valore negativo fino a quando non è positivo

int k = -13;
int modbase = 64;

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

int result = k % modbase;

Il risultato sarà ancora nella stessa classe di equivalenza.


1

x = x + m = x - min modulo m.
quindi -13 = -13 + 64in modulo 64 e -13 = 51in modulo 64.
supponiamo Z = X * d + r, se 0 < r < Xpoi in divisione Z/Xchiamiamo rresto.
Z % Xrestituisce il resto di Z/X.


1

La funzione mod è definita come la quantità di cui un numero supera il multiplo intero più grande del divisore che non è maggiore di quel numero. Quindi nel tuo caso di

-13 % 64

il multiplo intero più grande di 64 che non supera -13 è -64. Ora, quando sottrai -13 da -64 è uguale a 51-13 - (-64) = -13 + 64 = 51


0

Nella mia versione di Java JDK 1.8.0_05 -13% 64 = -13

potresti provare -13- (int (-13/64)) in altre parole eseguire il cast di divisione su un numero intero per eliminare la parte frazionaria quindi sottrarre dal numeratore Quindi numeratore- (int (numeratore / denominatore)) dovrebbe dare il corretto resto e segno



0

Secondo la sezione 15.17.3 del JLS, "L'operazione resto per gli operandi che sono numeri interi dopo la promozione numerica binaria produce un valore di risultato tale che (a / b) * b + (a% b) è uguale ad a. Questa identità vale anche nel caso speciale in cui il dividendo è l'intero negativo di grandezza maggiore possibile per il suo tipo e il divisore è -1 (il resto è 0). "

Spero che aiuti.


-1

Non credo che Java restituisca 51 in questo caso. Sto eseguendo Java 8 su un Mac e ottengo:

-13 % 64 = -13

Programma:

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

5
@XaverKapeller, no! Molte persone hanno sottolineato che matematicamente parlando -13 e 51 sono corretti. In Java, -13 è la risposta attesa, ed è anche quello che ho ottenuto, quindi non so come il mittente abbia ottenuto 51, è un mistero. I dettagli della modalità sul contesto potrebbero aiutare a rispondere correttamente a questa domanda.
Fabyen

@Xaver Kapeller: Come possono essere corretti entrambi 51 e -13? Java restituirebbe un solo valore ..
ceprateek

@XaverKapeller Come può una risposta che documenta ciò che Java effettivamente fa forse essere sbagliato?
Marchese di Lorne

@EJP Penso che 3 anni fa, quando ho scritto questo, fossi abbastanza stupido da valutare l'accuratezza matematica più della semplice realtà di come Java si occupa di questo. Grazie per avermi ricordato di rimuovere il mio stupido commento: D
Xaver Kapeller
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.