Para qual valor de i faz o loop while (i == i + 1) {} para sempre?
Corri através deste quebra-cabeças de um curso de programação avançada em um exame universitário do Reino Unido .
Considere o seguinte loop, no qual i é, até agora, não declarado:
Encontre a definição de i, que precede esse loop, de modo que o loop while continue para sempre.
A próxima pergunta, que fez a mesma pergunta para este trecho de código:
era óbvio para mim. É claro que nesta outra situação é, NaNmas estou realmente preso à anterior. Isso tem a ver com excesso? O que causaria esse loop para sempre em Java?
Alguma possibilidade de substituir o .equals()método? Como i não é declarado, podemos usar qualquer classe do que queremos.
@Raedwald estudando código "pouco profissional" torna-lo mais "profissional", então ... Enfim, é uma boa pergunta
De fato, em C # isso também funciona para tipos numéricos anuláveis ​​cujos valores são null, uma vez que null == nullé verdadeiro e null + 1é null.
@ EricDuminil: A situação é muito pior do que você imagina. Em muitas linguagens, a aritmética de ponto flutuante deve ser feita com pelo menos 64 bits de precisão especificados por um duplo, o que significa que pode ser feito com maior precisão ao capricho do compilador e , na prática, isso acontece . Posso apontar para você uma dúzia de perguntas neste site de programadores em C # que estão se perguntando por que 0.2 + 0.1 == 0.3altera seu valor dependendo das configurações do compilador, da fase da lua e assim por diante.
@EricDuminil: A culpa dessa bagunça recai sobre a Intel, que nos forneceu um chipset que faz aritmética de ponto flutuante de maior precisão e rapidez se os números puderem ser registrados, o que significa que os resultados de um cálculo de ponto flutuante podem alterar seus valores dependendo sobre como o agendador de registros no otimizador funciona hoje. Suas escolhas como designer de linguagem são, então, entre cálculos repetíveis e cálculos rápidos e precisos , e a comunidade que se preocupa com a matemática de ponto flutuante optará pelo último.
Antes de tudo, como o while (i == i + 1) {}loop não altera o valor de i, tornar esse loop infinito é equivalente a escolher um valor isatisfatório i == i + 1.
Existem muitos desses valores:
Vamos começar com os "exóticos":
A razão para a satisfação desses valores i == i + 1é declarada em
JLS 15.18.2. Operadores aditivos (+ e -) para tipos numéricos :
A soma de um infinito e um valor finito é igual ao operando infinito.
Isso não é surpreendente, pois a adição de um valor finito a um valor infinito deve resultar em um valor infinito.
Dito isto, a maioria dos valores ique satisfazem i == i + 1são simplesmente valores grandes double(ou float):
Os tipos doublee floattêm precisão limitada; portanto, se você usar um valor doubleou floatvalor suficientemente grande , a adição 1a ele resultará no mesmo valor.
Ou (double)(1L<<53)- oufloat i = (float)(1<<24)
— dave_thompson_085 28/11
@Ruslan: Qualquer matemático discordaria. Números de ponto flutuante fazem muito pouco sentido. Eles são não-associativos, não reflexivos (NaN! = NaN) e nem substituíveis (-0 == 0, mas 1/0! = 1 / -0). Portanto, a maioria das máquinas de álgebra é inaplicável.
— 28418 Kevin
@ Kevin enquanto os números de ponto flutuante não podem realmente fazer muito sentido em geral, o comportamento dos infinitos (que é o que é descrito nessa frase) foi projetado para fazer sentido.
@ Kevin Para ser justo com carros alegóricos, se você lida com infinitos ou valores indefinidos, também não pode assumir as propriedades que listou em álgebra.
@Kevin: IMHO, a matemática de ponto flutuante poderia ter feito muito mais sentido se eles substituíssem os conceitos de "zero positivo e negativo", sinalizando "infinitesimais" positivos, negativos e não assinados, juntamente com um "zero verdadeiro", e NaN igual a si mesmo. O zero verdadeiro pode se comportar como uma identidade aditiva em todos os casos, e alguma operação envolvendo divisão por infinitesimais perderia seu viés no sentido de assumir que os infinitesimais são positivos.
Esses quebra-cabeças são descritos em detalhes no livro "Java Puzzlers: Traps, Pitfalls and Corner Cases", de Joshua Bloch e Neal Gafter.
ambos resultarão em um loop infinito, porque a adição 1a um valor de ponto flutuante suficientemente grande não mudará o valor, porque não "preenche a lacuna" para seu sucessor 1 .
Uma observação sobre o segundo quebra-cabeça (para futuros leitores):
também resulta em um loop infinito, porque NaN não é igual a nenhum valor de ponto flutuante, incluindo ele próprio 2 .
1 - Java Puzzlers: armadilhas, armadilhas e casos de canto (capítulo 4 - Loopy Puzzlers).
Apenas uma idéia: e os booleanos?
Não é este o caso i + 1 == i?
depende do idioma. Muitos idiomas coagem automaticamente os booleanos a ints quando combinados com um int. Outros fazem o que você sugere - forçando o int a um booleano.
— 24518 Carl Witthoft
Esta pergunta é uma pergunta sobre Java e sua sugestão não passa na compilação em Java (que não possui um +operador que use a booleane a intcomo operandos).
@ Eran: essa é toda a ideia de sobrecarga do operador. Você pode fazer com que os booleanos Java se comportem como os C ++.