Pergunta
Eu tenho um programa que tenta encolher um double
até um número desejado. A saída que eu recebo é NaN
.
O que NaN
significa em java?
Solução
Tirado de esta página:
"Nan" significa "não um número". "NAN" é produzido se uma operação de ponto flutuante tiver alguns parâmetros de entrada que fazem com que a operação produza algum resultado indefinido. Por exemplo, 0,0 dividido por 0,0 é aritmeticamente indefinido. Tomar a raiz quadrada de um número negativo também é indefinido.
Outras dicas
NaN
significa “Não é um número” e é basicamente uma representação de um valor de ponto flutuante especial no IEE 754 Ponto flutuante padrão. Nan Geralmente significa que o valor é algo que não pode ser expresso com um número de ponto flutuante válido.
Uma conversão resultará nesse valor, quando o valor que está sendo convertido for outra coisa, por exemplo, ao converter uma string que não represente um número.
NaN
significa "não um número" e é o resultado de operações indefinidas em números de ponto flutuante, como, por exemplo, dividindo o zero por zero. (Observe que, ao dividir um número diferente de zero por zero, também é geralmente indefinido em matemática, isso não resulta em NAN, mas em infinito positivo ou negativo).
NaN
significa "não um número". É um valor de ponto flutuante especial que significa que o resultado de uma operação não foi definido ou não é representável como um número real.
Ver aqui Para obter mais explicação desse valor.
Nan significa não um número. É usado para significar qualquer valor que seja matematicamente indefinido. Como dividir 0,0 por 0,0. Você pode procurar aqui mais informações: https://web.archive.org/web/20120819091816/http://www.concentric.net/~ttwang/tech/javafloat.htm
Publique seu programa aqui se precisar de mais ajuda.
Nan = não um número.
Significa não um número. É uma representação comum para um valor numérico impossível em muitas linguagens de programação.
Não é um cara Java, mas em JS e em outros idiomas que eu uso, "não é um número", o que significa que alguma operação fez com que não se tornasse um número válido.
Significa literalmente "não um número". Suspeito que algo esteja errado com seu processo de conversão.
Confira a seção de um número em esta referência
Não é um valor de ponto flutuante válido (por exemplo, o resultado da divisão por zero)
Exemplo mínimo de execução
A primeira coisa que você precisa saber é que o conceito de NAN é implementado diretamente no hardware da CPU.
Todas as principais CPUs modernas parecem seguir IEEE 754 que especifica formatos de ponto flutuante e Nans, que são apenas valores especiais de flutuação, fazem parte desse padrão.
Portanto, o conceito será o muito semelhante em qualquer idioma, incluindo Java, que apenas emite código de ponto flutuante diretamente à CPU.
Antes de prosseguir, você pode primeiro ler as seguintes respostas que escrevi:
- Uma rápida atualização do formato de ponto flutuante IEEE 754: O que é um número de ponto flutuante subnormal?
- Alguns nan nan de nível inferior cobertos usando C / C ++: Qual é a diferença entre a nan silenciosa e a nan sinalizando?
Agora, para alguma ação Java. A maioria das funções de interesse que não estão no idioma principal vivem dentro java.lang.Float
.
Nan.java
import java.lang.Float;
import java.lang.Math;
public class Nan {
public static void main(String[] args) {
// Generate some NaNs.
float nan = Float.NaN;
float zero_div_zero = 0.0f / 0.0f;
float sqrt_negative = (float)Math.sqrt(-1.0);
float log_negative = (float)Math.log(-1.0);
float inf_minus_inf = Float.POSITIVE_INFINITY - Float.POSITIVE_INFINITY;
float inf_times_zero = Float.POSITIVE_INFINITY * 0.0f;
float quiet_nan1 = Float.intBitsToFloat(0x7fc00001);
float quiet_nan2 = Float.intBitsToFloat(0x7fc00002);
float signaling_nan1 = Float.intBitsToFloat(0x7fa00001);
float signaling_nan2 = Float.intBitsToFloat(0x7fa00002);
float nan_minus = -nan;
// Generate some infinities.
float positive_inf = Float.POSITIVE_INFINITY;
float negative_inf = Float.NEGATIVE_INFINITY;
float one_div_zero = 1.0f / 0.0f;
float log_zero = (float)Math.log(0.0);
// Double check that they are actually NaNs.
assert Float.isNaN(nan);
assert Float.isNaN(zero_div_zero);
assert Float.isNaN(sqrt_negative);
assert Float.isNaN(inf_minus_inf);
assert Float.isNaN(inf_times_zero);
assert Float.isNaN(quiet_nan1);
assert Float.isNaN(quiet_nan2);
assert Float.isNaN(signaling_nan1);
assert Float.isNaN(signaling_nan2);
assert Float.isNaN(nan_minus);
assert Float.isNaN(log_negative);
// Double check that they are infinities.
assert Float.isInfinite(positive_inf);
assert Float.isInfinite(negative_inf);
assert !Float.isNaN(positive_inf);
assert !Float.isNaN(negative_inf);
assert one_div_zero == positive_inf;
assert log_zero == negative_inf;
// Double check infinities.
// See what they look like.
System.out.printf("nan 0x%08x %f\n", Float.floatToRawIntBits(nan ), nan );
System.out.printf("zero_div_zero 0x%08x %f\n", Float.floatToRawIntBits(zero_div_zero ), zero_div_zero );
System.out.printf("sqrt_negative 0x%08x %f\n", Float.floatToRawIntBits(sqrt_negative ), sqrt_negative );
System.out.printf("log_negative 0x%08x %f\n", Float.floatToRawIntBits(log_negative ), log_negative );
System.out.printf("inf_minus_inf 0x%08x %f\n", Float.floatToRawIntBits(inf_minus_inf ), inf_minus_inf );
System.out.printf("inf_times_zero 0x%08x %f\n", Float.floatToRawIntBits(inf_times_zero), inf_times_zero);
System.out.printf("quiet_nan1 0x%08x %f\n", Float.floatToRawIntBits(quiet_nan1 ), quiet_nan1 );
System.out.printf("quiet_nan2 0x%08x %f\n", Float.floatToRawIntBits(quiet_nan2 ), quiet_nan2 );
System.out.printf("signaling_nan1 0x%08x %f\n", Float.floatToRawIntBits(signaling_nan1), signaling_nan1);
System.out.printf("signaling_nan2 0x%08x %f\n", Float.floatToRawIntBits(signaling_nan2), signaling_nan2);
System.out.printf("nan_minus 0x%08x %f\n", Float.floatToRawIntBits(nan_minus ), nan_minus );
System.out.printf("positive_inf 0x%08x %f\n", Float.floatToRawIntBits(positive_inf ), positive_inf );
System.out.printf("negative_inf 0x%08x %f\n", Float.floatToRawIntBits(negative_inf ), negative_inf );
System.out.printf("one_div_zero 0x%08x %f\n", Float.floatToRawIntBits(one_div_zero ), one_div_zero );
System.out.printf("log_zero 0x%08x %f\n", Float.floatToRawIntBits(log_zero ), log_zero );
// NaN comparisons always fail.
// Therefore, all tests that we will do afterwards will be just isNaN.
assert !(1.0f < nan);
assert !(1.0f == nan);
assert !(1.0f > nan);
assert !(nan == nan);
// NaN propagate through most operations.
assert Float.isNaN(nan + 1.0f);
assert Float.isNaN(1.0f + nan);
assert Float.isNaN(nan + nan);
assert Float.isNaN(nan / 1.0f);
assert Float.isNaN(1.0f / nan);
assert Float.isNaN((float)Math.sqrt((double)nan));
}
}
Correr com:
javac Nan.java && java -ea Nan
Resultado:
nan 0x7fc00000 NaN
zero_div_zero 0x7fc00000 NaN
sqrt_negative 0xffc00000 NaN
log_negative 0xffc00000 NaN
inf_minus_inf 0x7fc00000 NaN
inf_times_zero 0x7fc00000 NaN
quiet_nan1 0x7fc00001 NaN
quiet_nan2 0x7fc00002 NaN
signaling_nan1 0x7fa00001 NaN
signaling_nan2 0x7fa00002 NaN
nan_minus 0xffc00000 NaN
positive_inf 0x7f800000 Infinity
negative_inf 0xff800000 -Infinity
one_div_zero 0x7f800000 Infinity
log_zero 0xff800000 -Infinity
Então, com isso aprendemos algumas coisas:
Operações flutuantes estranhas que não têm nenhum resultado sensato dão a NAN:
0.0f / 0.0f
sqrt(-1.0f)
log(-1.0f)
gerar a
NaN
.Em C, é realmente possível solicitar que os sinais sejam levantados sobre essas operações com
feenableexcept
Para detectá -los, mas acho que não está exposto em Java: Por que a divisão inteira por zero 1/0 dá erro, mas o ponto flutuante 1/0.0 retorna "INF"?Operações estranhas que estão no limite de mais ou menos infinito, mas dão +- infinito em vez de nan
1.0f / 0.0f
log(0.0f)
0.0
Quase se enquadra nessa categoria, mas provavelmente o problema é que ela pode ir para o mais ou menos o infinito, por isso foi deixado como NAN.Se a NAN é a entrada de uma operação flutuante, a saída também tende a ser NAN
Existem vários valores possíveis para NAN
0x7fc00000
,0x7fc00001
,0x7fc00002
, embora x86_64 pareça gerar apenas0x7fc00000
.NAN e infinito têm representação binária semelhante.
Vamos quebrar alguns deles:
nan = 0x7fc00000 = 0 11111111 10000000000000000000000 positive_inf = 0x7f800000 = 0 11111111 00000000000000000000000 negative_inf = 0xff800000 = 1 11111111 00000000000000000000000 | | | | | mantissa | exponent | sign
A partir disso, confirmamos o que o IEEE754 especifica:
- Nan e infinitos têm expoente == 255 (todos os outros)
- Infinidades têm Mantissa == 0. Existem, portanto, apenas dois infinidade possíveis: + e -, diferenciados pelo bit de sinal
- Nan tem Mantissa! = 0. Existem, portanto, várias possibilidades, exceto para Mantissa == 0, que é o infinito
Os Nans podem ser positivos ou negativos (bit superior), embora isso não tenha efeito nas operações normais
Testado no Ubuntu 18.10 AMD64, OpenJDK 1.8.0_191.