Valeur de i pour (i == -i && i! = 0) pour renvoyer true en Java

101

J'ai la ifcondition suivante .

if (i == -i && i != 0)

Quelle valeur de iretournera truepour cette condition en Java?

Je suis incapable de penser à une telle valeur de iconsidérer la notation du complément à deux en Java.

J'aimerais aussi avoir une preuve algébrique de la réponse de cette condition (dans le contexte de Java)?

Ensoleillé
la source
2
Que
4
Notez que -0.0c'est aussi== 0
Peter Lawrey
2
écrivez-le commeif(i && i == -i)
Grijesh Chauhan
10
@GrijeshChauhan en Java? Êtes-vous sûr ?
Denys Séguret
3
@harold J'ai demandé à plusieurs reprises dans des interviews au cours des quatre dernières années et peu de gens comprennent vraiment même avec des indices.
Peter Lawrey

Réponses:

126

La seule intvaleur pour laquelle cela fonctionne est Integer.MIN_VALUE.

C'est parce que les entiers sont annulés en utilisant la méthode du complément à deux .

En utilisant

System.out.println(Integer.toBinaryString(Integer.MIN_VALUE));

vous voyez que Integer.MIN_VALUEc'est

10000000000000000000000000000000

Prendre la valeur négative se fait en échangeant d'abord 0et 1, ce qui donne

01111111111111111111111111111111

et en ajoutant 1, ce qui donne

10000000000000000000000000000000

Comme vous pouvez le voir dans le lien que j'ai donné, Wikipédia mentionne le problème avec les nombres les plus négatifs et précise que c'est la seule exception:

Le nombre le plus négatif dans le complément à deux est parfois appelé "le nombre étrange", car c'est la seule exception.

Bien sûr, vous avez le même phénomène Long.Min_Valuesi vous le stockez dans une longvariable.

Notez que cela est uniquement dû aux choix qui ont été faits concernant le stockage binaire des ints en Java . Une autre (mauvaise) solution aurait pu par exemple être de nier en changeant simplement le bit le plus significatif et en laissant les autres bits inchangés, cela aurait évité ce problème avec MIN_VALUE mais aurait fait 2 0valeurs différentes et une arithmétique binaire compliquée (comment auriez-vous incrémenté par exemple?).

Denys Séguret
la source
2
Il est intéressant de noter que les premiers ordinateurs binaires utilisaient l'implémentation de signe et de magnitude pour les entiers décrits dans votre dernier paragraphe; tout comme les nombres à virgule flottante IEE754. en.wikipedia.org/wiki/...
Dan Is Fiddling By Firelight
1
Re: "ceci est uniquement lié aux choix qui ont été faits concernant le stockage binaire des ints": Et les choix de la façon de gérer le débordement. La règle utilisée par Java n'est pas la même que la règle utilisée par (par exemple) C ou la règle utilisée par (par exemple) le ML standard, même si toutes ces règles fonctionnent sur une grande variété de systèmes.
ruakh
2
Il convient de mentionner qu'il est documenté sur la spécification Java : "Le langage de programmation Java utilise la représentation du complément à deux pour les entiers, et la plage des valeurs du complément à deux n'est pas symétrique, donc la négation du maximum négatif int ou long aboutit au même maximum nombre négatif."
chesterbr
25

La valeur que vous recherchez est Integer.MIN_VALUE.


J'aimerais aussi avoir une preuve algébrique de la réponse de cette condition (dans le contexte de java)?

C'est hors sujet pour Stack Exchange. Mais vous pouvez le faire à partir de la définition des entiers Java ( JLS 4.2 )

"Les types intégraux sont byte, short, int et long, dont les valeurs sont des entiers à complément à deux signés 8 bits, 16 bits, 32 bits et 64 bits ..."

et

"Les valeurs des types intégraux sont des entiers dans les plages suivantes ... Pour int, de -2147483648 à 2147483647, inclus"

et la définition de l'opérateur unaire Java '-' ( JLS 15.15.4 ):

"Pour les valeurs entières, la négation est la même que la soustraction à partir de zéro. Le langage de programmation Java utilise une représentation du complément à deux pour les entiers, et la plage des valeurs du complément à deux n'est pas symétrique, donc la négation du maximum négatif int ou long entraîne que même nombre négatif maximum. Un dépassement de capacité se produit dans ce cas, mais aucune exception n'est émise. Pour toutes les valeurs entières x, -x est égal à (~ x) +1. "

Stephen C
la source
3
Long.MIN_VALUE également.
Juvanis
1
qui est 100000 .., et si j'en reçois le compliment de 2, c'est à nouveau 011111 ... + 1 = 100000 ... mais vous le savez de haut en bas ou nous pouvons appliquer n'importe quelle logique?
Sunny
1
Comme je l'ai lu ... l'arithmétique int de Java est le mod arithmétique 2power32, donc je me demandais si nous pouvions prouver cette valeur en seulement 1 ou 2 lignes ... si c'est une grande preuve ... alors pas de problème.
Sunny
2
@Sunny ça ne peut pas être trop difficile à prouver. Dans la plage entière, tous les nombres positifs ont une contrepartie négative (donc i != -i). Cela laisse deux nombres dans la plage: 0et Integer.MIN_VALUE. À cause de i != 0votre si, il ne MIN_VALUEreste que.
Vincent van der Weele
1
@Heuster - ce raisonnement fonctionne ... mais cela dépend d'une ou deux hypothèses qui nécessitent une preuve.
Stephen C
18

En plus des réponses données jusqu'à présent ...

Il y a quatre valeurs au total

int i = Integer.MIN_VALUE;
long i = Long.MIN_VALUE;
Integer i = Integer.valueOf(Integer.MIN_VALUE);
Long i = Long.valueOf(Long.MIN_VALUE);

Les valeurs encapsulées sont déballées et sont donc également vraies pour cette expression.

Remarque: documents Math.abs.

public static int abs (int a)

Renvoie la valeur absolue d'une valeur int. Si l'argument n'est pas négatif, l'argument est renvoyé. Si l'argument est négatif, la négation de l'argument est renvoyée.

Notez que si l'argument est égal à la valeur de Integer.MIN_VALUE, la valeur int représentable la plus négative, le résultat est la même valeur, qui est négative.

et

public statique long abs (long a)

Renvoie la valeur absolue d'une valeur longue. Si l'argument n'est pas négatif, l'argument est renvoyé. Si l'argument est négatif, la négation de l'argument est renvoyée.

Notez que si l'argument est égal à la valeur de Long.MIN_VALUE, la valeur longue représentable la plus négative, le résultat est la même valeur, qui est négative.

Il est surprenant que Math.abs renvoie un nombre négatif. Cela se produit soit parce que a) il n'y a pas de valeurs positives pour -MIN_VALUE dans ces cas b) l'exécution du -calcul entraîne un débordement.

Ce qui est également intéressant, c'est pourquoi Byte.MIN_VALUE, Short.MIN_VALUE ne le font pas. Ceci est dû au -fait que le type change intpour ceux-ci et donc aucun débordement.

Character.MIN_VALUE n'a pas de problème car il est égal à 0.

Float.MIN_VALUE et Double.MIN_VALUE ont une signification différente. Il s'agit de la plus petite valeur représentable supérieure à zéro. Ainsi, ils ont des valeurs négatives valides qui ne sont pas elles-mêmes.

Peter Lawrey
la source
1
Je me posais des questions sur Byte.MIN_VALUE et d'autres possibilités, votre réponse l'a fourni. Merci
Cengiz Can
14

Comme les autres l'ont mentionné, cela n'est accompli que par Integer.MIN_VALUE. Quant à la preuve, permettez-moi d'offrir une explication plus facile à comprendre autrement qu'en binaire (bien qu'elle soit toujours enracinée dans cela).

Notez que Integer.MIN_VALUEest égal à -2^31ou -2147483648et Integer.MAX_VALUEest égal à 2^31-1ou 2147483647. -Integer.MIN_VALUEis 2^31, qui est maintenant trop grand pour un entier (puisqu'il est passé MAX_VALUE) provoquant ainsi un débordement d'entier, le faisant à Integer.MIN_VALUEnouveau. C'est le seul entier qui fait cela puisque MIN_VALUEc'est le seul nombre sans équivalent négatif à part 0.

Mark M
la source
2
@dystroy en fait je cherchais une explication, selon Mark, il n'y a pas de nombre tel que +2147483648 dans la plage int, donc le premier suspect devrait être ce nombre autre que 0. La plage est de -2 ^ n à 2 ^ n-1. Il n'y a donc pas d'équivalent positif à -2 ^ n. Ce n'est qu'une autre valeur int possible.
Sunny
1
Je n'ai pas expliqué en binaire car il était déjà couvert par quelqu'un d'autre (fondamentalement, int est une valeur 32 bits, c'est pourquoi il a ces limites). De plus, négatif ou négatif est positif, les conditions peuvent donc toujours s'appliquer.
Mark M
1
Curieusement en Java, le nombre ne 2147483648peut apparaître dans le code source que dans une circonstance: comme l'opérande de l'opérateur unaire moins (JLS 3.10.1).
Eric Jablow
6

Preuve algébrique provisoire, utilisant l' modulo 2^32arithmétique:

i == -ipeut être réécrit comme 2 * i == 0(en ajoutant des ideux côtés), ou i << 1 == 0.

Cette équation a deux solutions de la forme i == 0 >> 1, à savoir 0bet 10000000000000000000000000000000bobtenue en se déplaçant vers la gauche 0ou 1vers la gauche.

La solution i == 0étant exclue, il reste la solution i == 100000000000000000000000000000000b.

Yves Daoust
la source
0

Ce n'est peut-être pas trop instructif, mais au lieu de penser que vous pourriez exécuter ce code:

    for (int i = Integer.MIN_VALUE; i <= Integer.MAX_VALUE; i++)
    {
        if (i == -i && i != 0)
        {
            System.out.println(i);
        }
    }

pour voir qu'il imprime

-2147483648
-2147483648

infiniment :)

Kuba
la source
Comment pensez-vous que c'est infiniment?
JBelter
Parce que i <= Integer.MAX_VALUE ne sera jamais faux
Kuba
1
Ahh très vrai, je pensais avoir vu strictement<
JBelter