Valor de i para (i == -i && i! = 0) para devolver verdadero en Java

101

Tengo la siguiente ifcondición.

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

¿Qué valor de idevolverá truepara esta condición en Java?

No puedo pensar en tal valor de iconsiderar la notación de complemento a dos en Java.

También me encantaría tener una prueba algebraica de cualquier respuesta que tenga esta condición (en contexto con Java).

Soleado
fuente
2
¿Qué tal si (i! = null)
zxc
4
Tenga en cuenta que -0.0también es== 0
Peter Lawrey
2
escríbalo comoif(i && i == -i)
Grijesh Chauhan
10
@GrijeshChauhan ¿En Java? Estás seguro ?
Denys Séguret
3
@harold He preguntado en entrevistas muchas veces en los últimos cuatro años y pocas personas realmente lo entienden incluso con pistas.
Peter Lawrey

Respuestas:

126

El único intvalor por el que funciona es Integer.MIN_VALUE .

Es porque los enteros se niegan usando el método del complemento a dos .

Utilizando

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

ves que Integer.MIN_VALUEes

10000000000000000000000000000000

La toma del valor negativo se realiza intercambiando primero 0y 1, lo que da

01111111111111111111111111111111

y agregando 1, que da

10000000000000000000000000000000

Como puede ver en el enlace que le di, Wikipedia menciona el problema con los números más negativos y especifica que es la única excepción:

El número más negativo en el complemento de dos a veces se llama "el número extraño", porque es la única excepción.

Por supuesto, tiene el mismo fenómeno Long.Min_Valuesi lo almacena en unlong variable.

Tenga en cuenta que esto se debe únicamente a las elecciones que se hicieron con respecto al almacenamiento binario de ints en Java . Otra (mala) solución podría haber sido, por ejemplo, negar simplemente cambiando el bit más significativo y dejando los otros bits sin cambios, esto habría evitado este problema con MIN_VALUE pero habría hecho 2 0valores diferentes y una aritmética binaria complicada (¿cómo lo habría hecho? incrementado por ejemplo?).

Denys Séguret
fuente
2
Vale la pena señalar que las primeras computadoras binarias usaban la implementación de signo y magnitud para los enteros descritos en su último párrafo; al igual que los números de coma flotante IEE754. en.wikipedia.org/wiki/…
Dan Is Fiddling By Firelight
1
Re: "esto solo está relacionado con las elecciones que se hicieron con respecto al almacenamiento binario de ints": y las opciones de cómo manejar el desbordamiento. La regla que usa Java no es la misma que usa (digamos) C o la regla que usa (digamos) Standard ML, aunque todas se ejecutan en una amplia variedad de sistemas.
ruakh
2
Vale la pena mencionar que está documentado en la especificación de Java : "El lenguaje de programación Java usa una representación de complemento a dos para enteros, y el rango de valores de complemento a dos no es simétrico, por lo que la negación del máximo int negativo o largo da como resultado ese mismo máximo numero negativo."
chesterbr
25

El valor que busca es Integer.MIN_VALUE .


También me encantaría tener una prueba algebraica de cualquier respuesta que tenga esta condición (en contexto con java).

Eso es fuera de tema para Stack Exchange. Pero puede hacerlo a partir de la definición de enteros de Java ( JLS 4.2 )

"Los tipos integrales son byte, short, int y long, cuyos valores son enteros en complemento a dos con signo de 8 bits, 16 bits, 32 bits y 64 bits ..."

y

"Los valores de los tipos integrales son números enteros en los siguientes rangos ... Para int, de -2147483648 a 2147483647, inclusive"

y la definición del operador unario '-' de Java ( JLS 15.15.4 ):

"Para valores enteros, la negación es lo mismo que la resta de cero. El lenguaje de programación Java utiliza la representación de complemento a dos para los números enteros, y el rango de valores en complemento a dos no es simétrico, por lo que la negación del máximo int negativo o largo da como resultado que mismo número negativo máximo. Se produce un desbordamiento en este caso, pero no se produce ninguna excepción. Para todos los valores enteros x, -x es igual a (~ x) +1 ".

Stephen C
fuente
3
Long.MIN_VALUE también.
Juvanis
1
que es 100000 .., y si obtengo el cumplido de 2, nuevamente es 011111 ... + 1 = 100000 ... pero lo sabes muy bien o podemos aplicar alguna lógica?
Soleado
1
Como he leído ... la aritmética int de Java es aritmética mod 2power32, así que estaba pensando si podemos probar este valor en solo 1 o 2 líneas ... si es una gran prueba ... entonces no hay problema.
Soleado
2
@Sunny, no puede ser demasiado difícil de demostrar. En el rango de enteros, todos los números positivos tienen una contraparte negativa (entonces i != -i). Eso deja dos números en el rango: 0y Integer.MIN_VALUE. Por i != 0en tu si, solo MIN_VALUEqueda.
Vincent van der Weele
1
@Heuster: ese razonamiento funciona ... pero depende de una suposición o dos que requieren prueba.
Stephen C
18

Además de las respuestas dadas hasta ahora ...

Hay cuatro valores en 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);

Los valores ajustados se desenvuelven, por lo que también son válidos para esta expresión.

Nota: documentos Math.abs.

public static int abs (int a)

Devuelve el valor absoluto de un valor int. Si el argumento no es negativo, se devuelve el argumento. Si el argumento es negativo, se devuelve la negación del argumento.

Tenga en cuenta que si el argumento es igual al valor de Integer.MIN_VALUE, el valor int representable más negativo, el resultado es el mismo valor, que es negativo.

y

abdominales largos estáticos públicos (a largo)

Devuelve el valor absoluto de un valor largo. Si el argumento no es negativo, se devuelve el argumento. Si el argumento es negativo, se devuelve la negación del argumento.

Tenga en cuenta que si el argumento es igual al valor de Long.MIN_VALUE, el valor largo representable más negativo, el resultado es el mismo valor, que es negativo.

Es sorprendente que Math.abs pueda devolver un número negativo. Esto sucede porque a) no hay valores positivos para -MIN_VALUE en estos casos b) realizando el- cálculo da como resultado un desbordamiento.

Lo que también interesa es por qué Byte.MIN_VALUE, Short.MIN_VALUE no hacen esto. Esto se debe a que -cambia el tipo aint para estos y, por lo tanto, no hay desbordamiento.

Character.MIN_VALUE no tiene ningún problema porque es 0.

Float.MIN_VALUE y Double.MIN_VALUE tienen un significado diferente. Estos son el valor representable más pequeño mayor que cero. Por tanto, tienen valores negativos válidos que no son ellos mismos.

Peter Lawrey
fuente
1
Me preguntaba sobre Byte.MIN_VALUE y otras posibilidades, su respuesta proporcionó eso. Gracias
Cengiz Can
14

Como han mencionado los demás, esto solo se cumple con Integer.MIN_VALUE . En cuanto a la prueba, permítanme ofrecer una explicación más fácil de entender que no sea en binario (aunque todavía tiene sus raíces en eso).

Tenga en cuenta que Integer.MIN_VALUEes igual a -2^31o -2147483648y Integer.MAX_VALUEes igual a 2^31-1o 2147483647. -Integer.MIN_VALUEes 2^31, que ahora es demasiado grande para un Integer (ya que es pasado MAX_VALUE), lo que provoca un desbordamiento de Integer, Integer.MIN_VALUEvolviéndolo de nuevo. Es el único entero que hace esto, ya que MIN_VALUEes el único número sin equivalente negativo aparte de 0.

Mark M
fuente
2
@dystroy en realidad estaba buscando alguna explicación, según Mark, no hay un número como +2147483648 en el rango int, por lo que el primer sospechoso debería ser este número distinto de 0. El rango es -2 ^ n a 2 ^ n-1. Entonces no hay contraparte positiva para -2 ^ n. Este es solo otro valor int posible.
Soleado
1
No lo expliqué en binario porque ya estaba cubierto por otra persona (básicamente int es un valor de 32 bits, por eso tiene esos límites). Además, negativo de negativo es positivo, por lo que los términos aún pueden aplicarse.
Mark M
1
Curiosamente, en Java, el número 2147483648puede aparecer en el código fuente solo en una circunstancia: como operando del operador menos unario (JLS 3.10.1).
Eric Jablow
6

Prueba algebraica provisional, usando modulo 2^32 aritmética:

i == -ise puede reescribir como 2 * i == 0(agregando ien ambos lados), oi << 1 == 0 .

Esta ecuación tiene dos soluciones de la forma i == 0 >> 1, a saber, 0by se 10000000000000000000000000000000bobtiene cambiando en 0o1 hacia la izquierda.

Excluida la solución i == 0, queda la solución i == 100000000000000000000000000000000b.

Yves Daoust
fuente
0

Tal vez no sea demasiado educativo, pero en lugar de pensar que podría ejecutar este código:

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

para ver que se imprime

-2147483648
-2147483648

infinitamente :)

Kuba
fuente
¿Cómo crees que es infinitamente?
JBelter
Porque i <= Integer.MAX_VALUE nunca será falso
Kuba
1
Ahh muy cierto, pensé que vi estrictamente<
JBelter