Comment Java fait-il des calculs de module avec des nombres négatifs?

93

Est-ce que je fais mal le module? Parce qu'en Java -13 % 64est censé évaluer -13mais je reçois 51.

Jakir00
la source
102
@Dan Même sans un vide principal statique ... Je vois du code.
Joris Meys
22
Je reçois -13 & 64 == -13
Grodriguez
7
Comment obtenez-vous 51 heures de moins que -13.
Raedwald
3
Vous ne faites pas du tout de module. Il n'y a pas d'opérateur modulo en Java. %est un opérateur de reste.
Marquis of Lorne
3
Question déroutante: Java 8 donne -13, comme le disent d'autres personnes. Avec quelle version de Java avez-vous été censé obtenir cela?
Jan Żankowski

Réponses:

104

Les deux définitions du module des nombres négatifs sont utilisées - certains langages utilisent une définition et d'autres l'autre.

Si vous souhaitez obtenir un nombre négatif pour les entrées négatives, vous pouvez utiliser ceci:

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

De même si vous utilisiez une langue qui renvoie un nombre négatif sur une entrée négative et que vous préférez le positif:

int r = x % n;
if (r < 0)
{
    r += n;
}
Mark Byers
la source
3
Cela ne fonctionne pas bien si n est négatif. Si vous utilisez le même exemple de Java 7 Lang Spec (Section 15.17.3): (-5)% (-3) = -2. L'ajout de -3 ne fonctionnera pas. Vous devez ajouter la valeur absolue de n si vous voulez être sûr que cette valeur est positive.
partlov
6
En Java, le modulo négatif ne change rien, si vous utilisez quand même un Abs (), écrivez simplement r = x% abs (n). Je n'aime pas l'instruction if, je préfère écrire r = ((x% n) + n)% n. Concernant la puissance de 2 modulo (2,4,8,16, etc.) et la réponse positive, considérons le masque binaire r = x & 63.
Fabyen
3
Dans le contexte de Java (selon la balise de question), cette réponse est essentiellement "fausse". Compte tenu de l'expression x % y, A) si xest négatif, le reste est négatif, c'est-à-dire x % y == -(-x % y). B) le signe de yn'a aucun effet iex % y == x % -y
Bohème
72

Puisque "mathématiquement" les deux sont corrects:

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

L'une des options a dû être choisie par les développeurs de langage Java et ils ont choisi:

le signe du résultat est égal au signe du dividende.

Le dit dans les spécifications Java:

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

Caner
la source
8
La question est "pourquoi Java me donne-t-il -13 % 64 = 51alors que je m'attendais -13?".
Pascal Cuoq
5
@pascal: java vous donne la bonne définition en maths et la façon dont elle a été implémentée pour faire cela n'est pas ce que vous attendez de lui.
9
Le comportement mathématiquement sain est disponible dans Java 8: Math.floorMod
Jesse Glick
1
Quelque chose dans leur 15.17.3. Les exemples de % des opérateurs restants ne sont pas clairs. int result = (-5) % 3;donne -2. int result = (-3) % 5;donne -3. En général, int result = (-a) % b;donne la bonne réponse lorsque | -a | > b. Afin d'obtenir le résultat correct lorsque | -a | <b nous devrions envelopper le diviseur. int result = ((-a) % b) + b;pour négatif a ou int result = (((-a) % b) + b) % b;pour positif ou négatif a
Oz Edri
@Caner Je n'ai pas compris ça, comment les deux pourraient-ils être identiques?
Kishore Kumar Korada
20

Êtes-vous sûr de travailler en Java? car Java donne -13% 64 = -13 comme prévu. Le signe du dividende!

Keyxeq
la source
15

Votre résultat est faux pour Java. Veuillez expliquer comment vous y êtes parvenu (votre programme, implémentation et version de Java).

À partir de la spécification du langage Java

15.17.3 Opérateur de reste%
[...]
L'opération de reste pour les opérandes qui sont des entiers après promotion numérique binaire (§5.6.2) produit une valeur de résultat telle que (a / b) * b + (a% b) est égal à une.
15.17.2 Opérateur de division /
[...] La
division entière arrondit vers 0.

Puisque / est arrondi vers zéro (ce qui donne zéro), le résultat de% doit être négatif dans ce cas.

starblue
la source
Quelque chose dans leur 15.17.3. Les exemples de % des opérateurs restants ne sont pas clairs. int result = (-5) % 3;donne -2 int result = (-3) % 5;donne -3 En général, int result = (-a) % b;donne la bonne réponse quand | -a | > b Pour obtenir le résultat correct lorsque | -a | <b nous devrions envelopper le diviseur. int result = ((-a) % b) + b;pour un négatif a ou int result = (((-a) % b) + b) % b;pour un positif ou un négatif a.
Oz Edri
1
Votre commentaire n'est pas clair. La section définit le résultat correct et les exemples concordent avec cette définition. Pour votre exemple, (-3) % 5le résultat correct selon la définition est -3, et une implémentation correcte de Java devrait produire ce résultat.
starblue
Je suppose que je ne me suis pas expliqué correctement. Ce que je voulais dire par "la bonne réponse" quand | -a | <b, c'est que pour obtenir un résultat positif, nous devons "envelopper" le résultat donné à partir de a% b en y ajoutant b. Dans mon exemple, (-3)%5donne en effet -3, et si nous voulons le reste positif, nous devons lui ajouter 5, et le résultat sera2
Oz Edri
6

vous pouvez utiliser

(x % n) - (x < 0 ? n : 0);
ruslik
la source
3
@ruslik Vous pouvez également faire: ((x % k) + k) % k. (Bien que le vôtre soit probablement plus lisible.)
John Kurlak
2
@JohnKurlak Votre version fonctionne comme ceci: 4% 3 = 1 OU 4% -3 = -2 OU -4% 3 = 2 OU -4% -3 = -1 mais celui de ruslik fonctionne comme ceci: 4% 3 = 1 OU 4% -3 = 1 OU -4% 3 = -4 OU -4% -3 = 2
Joschua
1
@Joschua Merci de l'avoir signalé. Mon code est utile lorsque vous voulez que le résultat du module soit dans la plage de [0, sign(divisor) * divisor)au lieu de [0, sign(dividend) * divisor).
John Kurlak
3

Votre réponse est dans wikipedia: fonctionnement modulo

Il dit qu'en Java, le signe sur l'opération modulo est le même que celui du dividende. et puisque nous parlons du reste de l'opération de division est très bien, qu'il renvoie -13 dans votre cas, puisque -13/64 = 0. -13-0 = -13.

EDIT: Désolé, vous avez mal compris votre question ... Vous avez raison, java devrait donner -13. Pouvez-vous fournir plus de code environnant?

Nava Carmon
la source
2

L'arithmétique modulo avec des opérandes négatifs est définie par le concepteur du langage, qui peut laisser le soin à l'implémentation du langage, qui peut reporter la définition à l'architecture CPU.

Je n'ai pas pu trouver de définition du langage Java.
Merci Ishtar, Spécification du langage Java pour l' opérateur de reste% dit que le signe du résultat est le même que le signe du numérateur.

marcher
la source
1

Pour surmonter cela, vous pouvez ajouter 64(ou quelle que soit votre base de module) à la valeur négative jusqu'à ce qu'elle soit positive

int k = -13;
int modbase = 64;

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

int result = k % modbase;

Le résultat sera toujours dans la même classe d'équivalence.

Andreas
la source
1

x = x + m = x - mdans le module m.
donc -13 = -13 + 64en module 64 et -13 = 51en module 64.
supposons Z = X * d + r, si 0 < r < Xalors en division, Z/Xnous appelons rle reste.
Z % Xrenvoie le reste de Z/X.


la source
1

La fonction mod est définie comme la quantité par laquelle un nombre dépasse le plus grand multiple entier du diviseur qui n'est pas supérieur à ce nombre. Donc, dans votre cas de

-13 % 64

le plus grand multiple entier de 64 qui ne dépasse pas -13 est -64. Maintenant, lorsque vous soustrayez -13 de -64, cela équivaut à 51-13 - (-64) = -13 + 64 = 51

Salman Paracha
la source
0

Dans ma version de Java JDK 1.8.0_05 -13% 64 = -13

vous pouvez essayer -13- (int (-13/64)) en d'autres termes, faire une division transtypée en un entier pour se débarrasser de la partie fractionnaire puis soustraire du numérateur Donc numérateur- (int (numérateur / dénominateur)) devrait donner le bon reste et signe

Robert Green
la source
0

Dans les dernières versions de Java, vous obtenez -13%64 = -13. La réponse aura toujours le signe du numérateur.

vsn harish rayasam
la source
Dans quelle version ce changement a-t-il été effectué?
NightShadeQueen
Dans java 7, il mentionne clairement que le mod aura le signe du numérateur :)
vsn harish rayasam
@NightShadeQueen Cela n'a jamais été changé.
Marquis de Lorne
0

Selon la section 15.17.3 du JLS, "L'opération de reste pour les opérandes qui sont des nombres entiers après la promotion numérique binaire produit une valeur de résultat telle que (a / b) * b + (a% b) est égal à a. Cette identité est paire dans le cas particulier où le dividende est le nombre entier négatif de plus grande amplitude possible pour son type et le diviseur est -1 (le reste est 0). "

J'espère que cela pourra aider.

kudesiaji
la source
-1

Je ne pense pas que Java renvoie 51 dans ce cas. J'exécute Java 8 sur un Mac et j'obtiens:

-13 % 64 = -13

Programme:

public class Test {
    public static void main(String[] args) {
        int i = -13;
        int j = 64;
        System.out.println(i % j);
    }
}
ceprateek
la source
5
@XaverKapeller, non! De nombreuses personnes ont fait remarquer que mathématiquement parlant -13 et 51 sont corrects. En Java, -13 est la réponse attendue, et c'est ce que j'ai aussi, donc je ne sais pas comment le soumissionnaire a obtenu 51, c'est un mystère. Les détails du mode sur le contexte pourraient aider à répondre correctement à cette question.
Fabyen
@Xaver Kapeller: Comment 51 et -13 peuvent-ils tous deux être corrects? Java ne renverrait qu'une seule valeur ..
ceprateek
@XaverKapeller Comment une réponse qui documente ce que Java fait réellement peut-elle être erronée?
Marquis de Lorne
@EJP Je pense qu'il y a 3 ans, lorsque j'ai écrit cela, j'étais assez stupide pour valoriser la précision mathématique plus que la simple réalité de la façon dont java gère cela. Merci de me rappeler de supprimer mon commentaire stupide: D
Xaver Kapeller