Como pode "while (i == i);" ser um loop não infinito em um único aplicativo encadeado?

141

Acabei de receber uma pergunta que não posso responder.

Suponha que você tenha essa definição de loop em Java:

while (i == i) ;

Qual é o tipo ie o valor de ise o loop não é um loop infinito e o programa está usando apenas um thread ?

Zizzencs
fonte
7
oh, pelo amor de Deus, as pessoas teriam a honra de comentar o motivo pelo qual votaram negativamente? isso está marcado como um enigma, qual é o problema ???
user54579
10
Eu acho que algumas pessoas não conseguem parar de votar por qualquer coisa.
FerranB 22/01/09
1
Bah, desculpe-me por causar isso: / Eu realmente só queria a resposta e não consegui resolvê-la.
Zizzencs 22/01/09
1
@nickolai, essa é a natureza do SO - a redução de drive-by é infelizmente uma realidade e a ideia de exigir um comentário foi discutida e rejeitada. Mas parece que a "comunidade" é a favor dessa questão, afinal.
23411
1
Um dos truques desse tipo de pergunta é que as pessoas assumem o tipo de certos nomes de variáveis, ou seja, i é um int, d é um duplo, s é uma string ou um curto, ch é um char, l é um longo, b para byte ou booleano. Você deve se perguntar que tipo é sugerido e qual poderia ser.
354 Peter Lawrey

Respostas:

125
double i = Double.NaN;

A API para Double.equals () explica a resposta: "Double.NaN == Double.NaN tem o valor false". Isso é elaborado na Especificação da Linguagem Java em " Tipos, Formatos e Valores de Ponto Flutuante ":

NaNé não ordenada, de modo que o numérico operadores de comparação <, <=, >, e >= de retorno false, se um ou ambos os operandos são NaN. O operador de igualdade ==retorna falsese um dos operandos for NaNe o operador de desigualdade !=retorna truese um dos operandos for NaN. Em particular, x!=xé truese e somente se xéNaN e (x<y) == !(x>=y)será falsese xou yé NaN.

Zach Scrivena
fonte
1
OH, então você pode fazer "Não é um número"!
Filip Ekberg
12
é matematicamente sólido, por que um número irreal é igual a outro? 5/0! = Sqrt (-4)
Gordon Gustafson
2
@CrazyJugglerDrummer: Talvez, mas da mesma forma x == xsempre deve ser verdade. Por que algo não deveria se igualar?
Bart van Heukelom 28/07
1
Bart: porque realmente, desconhecido nem sempre é igual a desconhecido. Às vezes é útil, por isso é que bancos de dados têm NULL ...
Konerak
2
@inovaovao: não, em um banco de dados, null=nullé nulo. NULL IS NULLé 1.
Konerak
29

O valor de ié então inválido. "Não é um número".

Depois de pesquisar no google, descobri que você PODE ter NaN (não é um número) em Java! Portanto, um número de ponto flutuante é o tipo de dados e o valor é NaN. Veja aqui

Filip Ekberg
fonte
12
Sim, é isso. O valor de i é Jon Skeet.
Andrew Rollings
Eu geralmente odeio pessoas que votam negativamente sem motivo ... Fui o primeiro a dizer "Não é um número", mas não achei que o java pudesse lidar com isso, uma vez que não lida com nada mais legal.
Filip Ekberg
12
double i = Double.NaN;

NaN não é igual a nada, inclusive a si próprio.

Bill the Lizard
fonte
9
float i = Float.NaN;
while(i == i) ;
System.out.println("Not infinite!");
Aaron Maenpaa
fonte
8

Não tenho certeza, mas acredito que (i == i) não é uma operação atômica no processo multithread, por isso, se o valor de i for alterado por outro encadeamento entre os toques de seu valor para empilhar no encadeamento que executa o loop, essa condição poderá seja falso.

okutane
fonte
8

Como outros disseram que é NaN, fiquei curioso sobre a implementação oficial (JDK 6) Double.isNaNe observe:

/**
 * Returns <code>true</code> if the specified number is a
 * Not-a-Number (NaN) value, <code>false</code> otherwise.
 *
 * @param   v   the value to be tested.
 * @return  <code>true</code> if the value of the argument is NaN;
 *          <code>false</code> otherwise.
 */
static public boolean isNaN(double v) {
    return (v != v);
}
Bart van Heukelom
fonte
2

Pense em Nan como o equivalente à exceção, mas usa um valor mágico dentro de um cálculo. Como um cálculo falhou - por exemplo, raiz quadrada de um negativo, divida por zero etc. - não faz sentido compará-los com qualquer outra coisa. Afinal, se dividir por zero é um nan, é equivalente à raiz quadrada de -2 ou à raiz quadrada de -3?

Nan permite um cálculo que inclui uma etapa que retorna uma resposta inválida para ser concluída sem a introdução de exceções extras. Para verificar se o valor da resposta é simplesmente teste para não-incondicionalidade (isto é, se não for o caso) via Float.isNan () ou equivalente.

mP.
fonte
3
Seria mais fácil pensar nele como exceto, mas se eu realmente soubesse o que era um exceto, era :-).
23411
2

Eu adicionaria

float i = Float.NaN;

assim como

double i = Double.NaN;

Um truque comum nesse tipo de pergunta é na suposição de que você é um int. Outras suposições comuns podem ser s é uma String, x, y são um duplo, ch é um char, b é um byte etc. Se você vir uma pergunta como essa, pode apostar que 'i' não é o seu tipo esperado.

Uma pergunta semelhante é; Isso nunca faz loop, o que é 'x'

while(x == x && x != x + 0) { }

Outra pergunta de que gosto bastante é; Esse loop é um loop infinito, quais são os possíveis valores de x. (: Conto doze deles :)

while(x != 0 && x == -x) { }
Peter Lawrey
fonte
0

Eu sei que essa é uma pergunta sobre Java, mas considerar a pergunta para outras linguagens é intrigante.

Em C, um tipo simples como 'int' pode exibir 'termina' antes que o universo esfrie 'comportamento' se 'i' for declarado como volátil (para que o compilador seja forçado a fazer duas leituras de 'i' para cada iteração) e se 'i' estivesse na memória, onde outra coisa poderia afetá-lo. Então o loop terminaria quando 'i' mudasse entre as duas leituras de uma única iteração. ( Adicionado : um local possível - em um microcomputador onde 'i' está realmente localizado no endereço de uma porta de E / S, talvez conectado a um sensor de posição. Seria mais plausível se 'i' fosse uma variável de ponteiro ( um ponteiro para a memória volátil) e a declaração foi 'while (*i == *i); '.)

Como evidenciado por outras respostas, em C ++, o operador '==' pode ser fornecido pelo usuário se i for de uma classe definida pelo usuário; portanto, tudo pode ser possível.

Assim como NaN, em uma linguagem baseada em SQL, o loop não seria infinito se o valor de i fosse NULL; no entanto, qualquer valor que não seja NULL tornaria o loop infinito. É como o Java, onde qualquer número (ao contrário do NaN) torna o loop infinito.

Não vejo o construto tendo nenhum uso prático, mas é uma pergunta interessante.

Jonathan Leffler
fonte
0

Fiquei surpreso ao não ver esta solução:

while (sin(x) == sin(x)) //probably won't eval to true

Em resposta a um comentário, tente executar o seguinte:

double x = 10.5f;
assert (x == asin(sin(x)));

x sempre deve ser igual ao arco-seno (sin (x)) em teoria, mas na prática não é.

jkeys
fonte
3
Por que não? Você está fazendo exatamente o mesmo cálculo nos mesmos dados, os dois resultados conterão exatamente o mesmo erro.
18730 Loren Pechtel
Não me lembro exatamente onde o li, mas, dependendo da sua máquina / implementação, o pecado (x) em uma chamada de função tem uma chance minúscula de igualar o pecado (x) de uma chamada diferente. Tem a ver com a precisão dos dígitos do ponto flutuante (algo é especial nas funções trigonométricas que as fazem não retornar o mesmo valor duas vezes).
jkeys
Veja minha atualização. Arcsine "desfaz" o pecado de x, então eles devem ser iguais, mas não são.
jkeys
Isso não é a mesma coisa. Como Loren disse, você está executando exatamente a mesma operação x, o que deve gerar exatamente o mesmo resultado com a mesma imprecisão. O Arcsin não pode reverter o resultado de um pecado com números de ponto flutuante porque o valor passado para asin()não será exatamente exato. Portanto, o resultado de asin()será impreciso, tornando x == asin(sin(x))falso. Além disso, o arcsin não necessariamente "desfaz" uma operação sin - a função sin pode fornecer o mesmo resultado para vários valores de x, e é por isso que asin()apenas retorna números entre -π / 2 e π / 2.
HBW
2
Em outras palavras, o arcsin nem sempre pode "desfazer" a função sin, porque é impossível para o arcsin saber qual era o ângulo original. Por exemplo, o pecado de π / 2 e 5π / 2 dá 1. Mas o que é arcsin (1)? Obviamente, não pode devolver os dois, certo? Portanto, o resultado de arcsin deve ser restrito a um intervalo de 2π radianos, o que significa que ele não pode realmente desfazer o resultado da função sin, a menos que o ângulo original esteja entre 0 e 2π ou, no caso de C, -π / 2 e π / 2. (De fato, arcsin (sin (5π / 2)) = π / 2.) De qualquer forma, essa foi uma explicação realmente longa, mas espero que ajude a esclarecer quaisquer equívocos.
HBW
0

Não loop infinito, um segmento :)

import static B.*;
public class A {
    public static void main(String[] args) {
        System.out.println("Still Running");
        while (i == i) ;
    }
}


public class B {

    public static int i;
    static {
        System.exit(0);
    }
}
Andrey
fonte
-1

i == inão é atômico. Comprovado por esse programa:

static volatile boolean i = true;
public static void main(String[] args) throws InterruptedException
{
    new Thread() {
        @Override
        public void run() {
            while (true) {
                i = !i;
            }
        }
    }.start();

    while (i == i) ;
    System.out.println("Not atomic! i: " + i);
}

Atualizar Aqui está mais um exemplo de loop não infinito (nenhum novo encadeamento é criado).

public class NoNewThreads {
    public static void main(String[] args) {
        new NoNewThreads();
        System.gc();
        int i = 500;
        System.out.println("Still Running");
        while (i == i) ;
    }

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        Thread.sleep(1000);
        System.exit(0);
    }
}
Andrey
fonte
@ Charles Goodwin O que você diz ao fato de que não há possibilidade de escrever um programa Java usando um thread :), portanto, todas as outras soluções usam pelo menos dois threads (exatamente o mesmo que o meu segundo programa na seção 'Atualizar').
Andrey
Isso não é frear o loop. Qualquer código depois while (i == i);nunca será executado.
aalku
Finalize usa outro thread, mas é uma coisa boa a salientar. É a razão pela qual a pergunta original dizia "e o programa usa apenas um segmento". Meio que explicitamente afirmando que esta é a resposta óbvia e eles desejam que você procure mais.
Bill K