Valor de i para (i == -i && i! = 0) retornar verdadeiro em Java

101

Eu tenho a seguinte ifcondição.

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

Qual valor de iretornará truepara esta condição em Java?

Não consigo pensar em qualquer valor de iconsiderar a notação de complemento de dois em Java.

Eu também adoraria ter uma prova algébrica de qualquer resposta que essa condição tenha (no contexto com Java).

Ensolarado
fonte
2
que tal if (i! = null)
zxc
4
Observe que -0.0também é== 0
Peter Lawrey
2
escreva comoif(i && i == -i)
Grijesh Chauhan
10
@GrijeshChauhan em Java? Você tem certeza ?
Denys Séguret
3
@harold Eu perguntei em entrevistas muitas vezes nos últimos quatro anos e poucas pessoas realmente entendem mesmo com dicas.
Peter Lawrey

Respostas:

126

O único intvalor para o qual funciona é Integer.MIN_VALUE.

É porque os inteiros são negados usando a forma de complemento de dois .

Usando

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

você vê que Integer.MIN_VALUEé

10000000000000000000000000000000

Obter o valor negativo é feito primeiro trocando 0e 1, o que dá

01111111111111111111111111111111

e adicionando 1, o que dá

10000000000000000000000000000000

Como você pode ver no link que eu dei, a Wikipedia menciona o problema com os números mais negativos e especifica que é a única exceção:

O número mais negativo no complemento de dois às vezes é chamado de "o número estranho", porque é a única exceção.

Claro que você tem o mesmo fenômeno Long.Min_Valuese você armazená-lo em uma longvariável.

Observe que isso se deve apenas às escolhas feitas em relação ao armazenamento binário de ints em Java . Outra (má) solução poderia, por exemplo, ter sido negar simplesmente mudando o bit mais significativo e deixando os outros bits inalterados, isso teria evitado este problema com MIN_VALUE, mas teria feito 2 0valores diferentes e aritmética binária complicada (como você faria incrementado, por exemplo?).

Denys Séguret
fonte
2
É importante notar que os primeiros computadores binários usavam a implementação de sinal e magnitude para inteiros descrita em seu último parágrafo; assim como os números de ponto flutuante IEE754. en.wikipedia.org/wiki/…
Dan Is Fiddling By Firelight
1
Re: "Isso está relacionado apenas às escolhas que foram feitas em relação ao armazenamento binário de ints": E as escolhas de como lidar com o estouro. A regra que o Java usa não é a mesma que a regra usada por (digamos) C ou a regra usada por (digamos) ML padrão, embora todas elas sejam executadas em uma ampla variedade de sistemas.
ruakh
2
Vale a pena mencionar que está documentado na especificação Java : "A linguagem de programação Java usa representação de complemento de dois para inteiros, e o intervalo de valores de complemento de dois não é simétrico, então a negação do máximo negativo int ou resultados longos no mesmo máximo número negativo."
chesterbr
25

O valor que você está procurando é Integer.MIN_VALUE.


Eu também adoraria ter uma prova algébrica de qualquer resposta que essa condição tenha (no contexto com java).

Isso está fora do tópico do Stack Exchange. Mas você poderia fazer isso a partir da definição de inteiros Java ( JLS 4.2 )

"Os tipos integrais são byte, short, int e long, cujos valores são inteiros de complemento de dois sinais de 8 bits, 16 bits, 32 bits e 64 bits ..."

e

"Os valores dos tipos integrais são inteiros nos seguintes intervalos ... Para int, de -2147483648 a 2147483647, inclusive"

e a definição do operador '-' unário Java ( JLS 15.15.4 ):

"Para valores inteiros, negação é o mesmo que subtração de zero. A linguagem de programação Java usa representação de complemento de dois para inteiros, e o intervalo de valores de complemento de dois não é simétrico, então a negação do máximo negativo interno ou longo resulta em que mesmo número negativo máximo. O estouro ocorre neste caso, mas nenhuma exceção é lançada. Para todos os valores inteiros x, -x é igual a (~ x) +1. "

Stephen C
fonte
3
Long.MIN_VALUE também.
Juvanis
1
que é 100000 .., e se eu obtiver um elogio de 2, é novamente 011111 ... + 1 = 100000 ... mas você sabe disso no início da sua cabeça ou podemos aplicar alguma lógica?
Ensolarado de
1
Como eu li .. aritmética int de Java é aritmética mod 2power32, então eu estava pensando se podemos provar esse valor em apenas 1 ou 2 linhas .. se for uma grande prova .. então não há problema.
Ensolarado de
2
@Sunny, não pode ser muito difícil de provar. No intervalo de inteiros, todos os números positivos têm uma contraparte negativa (então i != -i). Isso deixa dois números no intervalo: 0e Integer.MIN_VALUE. Por causa do i != 0seu se, só MIN_VALUEresta.
Vincent van der Weele
1
@Heuster - esse raciocínio funciona ... mas depende de uma ou duas suposições que exigem prova.
Stephen C
18

Além das respostas dadas até agora ...

Existem quatro valores no 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);

Os valores agrupados são desempacotados, portanto, também são verdadeiros para esta expressão.

Nota: documentos Math.abs.

público estático int abs (int a)

Retorna o valor absoluto de um valor int. Se o argumento não for negativo, o argumento será retornado. Se o argumento for negativo, a negação do argumento é retornada.

Observe que se o argumento for igual ao valor de Integer.MIN_VALUE, o valor int representável mais negativo, o resultado é o mesmo valor, que é negativo.

e

abs longo estático público (a longo)

Retorna o valor absoluto de um valor longo. Se o argumento não for negativo, o argumento será retornado. Se o argumento for negativo, a negação do argumento é retornada.

Observe que se o argumento for igual ao valor de Long.MIN_VALUE, o valor longo representável mais negativo, o resultado é o mesmo valor, que é negativo.

É surpreendente que Math.abs possa retornar um número negativo. Isso acontece porque a) não há valores positivos para -MIN_VALUE nesses casos b) realizar o -cálculo resulta em um estouro.

O que também é interessante é por que Byte.MIN_VALUE, Short.MIN_VALUE não fazem isso. Isso ocorre porque o -tipo muda intpara esses e, portanto, não há estouro.

Character.MIN_VALUE não tem problema porque é 0.

Float.MIN_VALUE e Double.MIN_VALUE têm um significado diferente. Estes são os menores valores representáveis ​​maiores que zero. Assim, eles têm valores negativos válidos que não são eles próprios.

Peter Lawrey
fonte
1
Gostaria de saber sobre Byte.MIN_VALUE e outras possibilidades, sua resposta forneceu isso. Obrigado
Cengiz Can
14

Como os outros mencionaram, isso só é cumprido por Integer.MIN_VALUE. Como prova, deixe-me oferecer uma explicação mais fácil de entender que não seja binária (embora ainda esteja enraizada nisso).

Observe que Integer.MIN_VALUEé igual a -2^31ou -2147483648e Integer.MAX_VALUEé igual a 2^31-1ou 2147483647. -Integer.MIN_VALUEis 2^31, que agora é muito grande para um Integer (já que já passou MAX_VALUE), causando um estouro de Integer, tornando-o Integer.MIN_VALUEnovamente. É o único inteiro que faz isso, pois MIN_VALUEé o único número sem equivalente negativo além de 0.

Mark M
fonte
2
@dystroy, na verdade, eu estava procurando alguma explicação, de acordo com Mark, não existe tal número como +2147483648 no intervalo interno, então a primeira suspeita deve ser este número diferente de 0. O intervalo é -2 ^ n a 2 ^ n-1. Portanto, não há contrapartida positiva para -2 ^ n. Este é apenas outro valor int possível.
Ensolarado de
1
Não expliquei em binário, pois já foi coberto por outra pessoa (basicamente int é um valor de 32 bits, por isso tem esses limites). Além disso, negativo de negativo é positivo, portanto, os termos ainda podem ser aplicados.
Mark M
1
Curiosamente, em Java, o número 2147483648pode aparecer no código-fonte apenas em uma circunstância: como o operando do operador menos unário (JLS 3.10.1).
Eric Jablow
6

Prova algébrica experimental, usando modulo 2^32aritmética:

i == -ipode ser reescrito como 2 * i == 0(adicionando iem ambos os lados) ou i << 1 == 0.

Essa equação tem duas soluções da forma i == 0 >> 1, a saber, 0be 10000000000000000000000000000000bobtida deslocando-se para a esquerda 0ou 1para a esquerda.

Excluída a solução i == 0, resta a solução i == 100000000000000000000000000000000b.

Yves Daoust
fonte
0

Talvez não seja muito educativo, mas em vez de pensar, você poderia executar 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 se imprime

-2147483648
-2147483648

infinitamente :)

Kuba
fonte
Como você acha que é infinito?
JBelter
Porque i <= Integer.MAX_VALUE nunca será falso
Kuba
1
Ahh muito verdade, pensei ter visto estritamente<
JBelter