我有一个程序试图缩小double
到所需的数量。我得到的输出是NaN
。
NaN
在Java 中是什么意思?
我有一个程序试图缩小double
到所需的数量。我得到的输出是NaN
。
NaN
在Java 中是什么意思?
Answers:
取自此页面:
“ NaN”代表“不是数字”。如果浮点运算具有一些输入参数,导致该运算产生一些未定义的结果,则会生成“ Nan”。例如,0.0除以0.0在算术上是不确定的。负数的平方根也是不确定的。
NaN
具有有趣的特性,它是唯一的“数字”,在比较时与自身不同。因此,一个普通的(并且在许多语言中是唯一的)测试数字x
是否NaN
如下:boolean isNaN(x){return x != x;}
i
与像蟒蛇处理一些语言非常好,它...它可能不是在的情况下java
你
NaN代表非数字。它用于表示数学上未定义的任何值。就像将0.0除以0.0。您可以在此处查看更多信息: https //web.archive.org/web/20120819091816/http //www.concentric.net/~ttwang/tech/javafloat.htm
如果需要更多帮助,请在此处发布程序。
最小的可运行示例
您必须了解的第一件事是,NaN的概念直接在CPU硬件上实现。
所有主要的现代CPU似乎都遵循IEEE 754,该标准规定了浮点格式,而NaN(只是特殊的浮点值)是该标准的一部分。
因此,该概念在所有语言中都非常相似,包括Java,Java只是直接向CPU发送浮点代码。
在继续之前,您可能需要先阅读我写的以下答案:
现在进行一些Java操作。大多数不在核心语言中的功能都位于内部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));
}
}
运行:
javac Nan.java && java -ea Nan
输出:
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
因此,我们从中学到了一些东西:
没有任何明智结果的怪异浮动操作会导致NaN:
0.0f / 0.0f
sqrt(-1.0f)
log(-1.0f)
产生一个NaN
。
在C语言中,实际上可以请求在此类操作上引发信号以feenableexcept
检测它们,但我认为Java中并未公开它:为什么整数除以零1/0会产生错误,而浮点数却是1 / 0.0返回“ Inf”?
加上正负无穷大的怪异运算,但确实给出了+-无限而不是NaN
1.0f / 0.0f
log(0.0f)
0.0
几乎属于这一类,但可能的问题是它可以达到正负无穷大,因此将其保留为NaN。
如果NaN是浮动运算的输入,则输出也往往是NaN
有几种可能的值楠0x7fc00000
,0x7fc00001
,0x7fc00002
,虽然x86_64的似乎只对产生0x7fc00000
。
NaN和无穷大具有相似的二进制表示形式。
让我们分解其中的一些:
nan = 0x7fc00000 = 0 11111111 10000000000000000000000
positive_inf = 0x7f800000 = 0 11111111 00000000000000000000000
negative_inf = 0xff800000 = 1 11111111 00000000000000000000000
| | |
| | mantissa
| exponent
|
sign
由此我们可以确定IEEE754的规定:
NaN可以是正数或负数(最高位),尽管它对正常操作没有影响
在Ubuntu 18.10 amd64,OpenJDK 1.8.0_191中进行了测试。
不是有效的浮点值(例如,被零除的结果)