Java 中的 NaN
概述
简单来说可以认为NaN是一个数字数据类型变量值,这个类型变量被定义为这不是一个数字。
在这篇文章中,我们对 Java 中的NaN进行一些简单的描述和说明和在那些操作的过程中可以尝试这个值,和可以如何去避免。
NaN 通常表示一个无效的操作结果。例如,你尝试将数字 0 去除以 0,这个在数学中是不存在的,同时在 Java 中定义 NaN 也确实就是通过这个不存在的操作来定义的。
我们通常也使用NaN来表示不能显示的变量值。例如,我们对数字 -1 开平方根的时候,也是这种情况。
例如我们可以只在负数的情况下描述 value (i) 。
在页面IEEE 754 - 维基百科,自由的百科全书中对非数值 NaN 的定义进行了说明。你可以阅读上面的文章来了解更多有关 NaN 的定义。
在 Java 中,只有浮点数据类型float和double实现了这个标准。
Java 咋 使用Float.NaN和Double.NaN来定义了 NaN 构造函数。
nan-c-01791×543 47.9 KB
在 double 中一个常量 Not-a-Number (NaN) 定义了这个值,这个值等于Double.longBitsToDouble(0x7ff8000000000000L)的返回值。
和
在 float 中一个常量 Not-a-Number (NaN) 定义了这个值,这个值等于Float.intBitsToFloat(0x7fc00000)的返回值。
在 Java 中没有针对其他数据类型定义的 NaN 了。
在 Java 中,如果我们开始写一个方法的时候,我们应该需要针对方法的输入数据进行检查,以确保输入数据的准确和输入数据在允许的范围内。
NaN在绝大部分情况下都不是一个有效的输入参数,因此在 Java 的方法中,我需要对输入的参数进行比较,以确保输入的参数中的值不是NaN,然后我们能够对输入参数进行正确的处理。
NaN不能余任何浮点类型数据进行比较,这就表示,任何有NaN参与的比较都会返回 false(这里只有一个例外为 “!=” 将会返回 true)。
我们将会得到 针对x != x表达式,如果 x 是 NaN 的话,我们将会在这里得到 true。
考察下面的代码:
System.out.println("NaN == 1 = "+ (NAN ==1));System.out.println("NaN > 1 = "+ (NAN >1));System.out.println("NaN < 1 = "+ (NAN <1));System.out.println("NaN != 1 = "+ (NAN !=1));System.out.println("NaN == NaN = "+ (NAN == NAN));System.out.println("NaN > NaN = "+ (NAN > NAN));System.out.println("NaN < NaN = "+ (NAN < NAN));System.out.println("NaN != NaN = "+ (NAN != NAN));
下面的内容就是针对上面代码的输出结果。
NaN==1=falseNaN>1=falseNaN<1=falseNaN!=1=trueNaN==NaN=falseNaN>NaN=falseNaN
所以,我们不能够通过比较来检查数据是不是 NaN。
事实上,我们也不应该用 “==” 或 “!= “ 来对 double 或者 flat 类型的数据进行比较。
所以,我们可以使用 “x != x”* 表达式来检查 NaN 是不是为 true。
更多的,我们可能会使用Float.isNaN和Double.isNaN方法来检查这个输入的参数值是不是 NaN。
实际上,这种方法更好,因为这能够让代码更加易读。
考察下面的代码:
double x =1;System.out.println(x +" is NaN = "+ (x != x));System.out.println(x +" is NaN = "+ (Double.isNaN(x))); x =Double.NaN;System.out.println(x +" is NaN = "+ (x != x));System.out.println(x +" is NaN = "+ (Double.isNaN(x)));
下面内容就是上面代码的输出。
1.0isNaN=false1.0isNaN=falseNaNisNaN=trueNaNisNaN=true
当我们对float和double类型进行操作和计算的时候,我们应该注意某些操作是可能会产生NaN值的。
一些针对浮点计算的方法和操作是会产生NaN这个值来替换掉可能抛出的异常,换句话说就是有些操作不会抛出异常,但是返回的结果是 NaN。
最常见的情况就是对数字进行计算的时候,这个算法在数学中还没有被定义,或者被定义是不可以这样做的。
如最常见的 0 除以 0 的情况。
因为在数学中,这种情况被定义为非法的。
System.out.println("Undefined Operations Produce NaN");finaldouble ZERO =0; System.out.println("ZERO / ZERO = "+ (ZERO / ZERO)); System.out.println("INFINITY - INFINITY = "+ (Double.POSITIVE_INFINITY -Double.POSITIVE_INFINITY)); System.out.println("INFINITY * ZERO = "+ (Double.POSITIVE_INFINITY * ZERO)); System.out.println();
上面的代码将会有下面的输出:
Undefined Operations ProduceNaNZERO / ZERO =NaNINFINITY - INFINITY =NaNINFINITY * ZERO =NaN
同时有关数字的操作和计算的结果并不能产生数字的情况下也会输出为 NaN。
System.out.println("Operations with no real results produce NaN"); System.out.println("SQUARE ROOT OF -1 = "+ Math.sqrt(-1)); System.out.println("LOG OF -1 = "+ Math.log(-1)); System.out.println();
上面的代码的结果如下:
Operationswithnoreal results produceNaNSQUARE ROOT OF-1=NaNLOG OF-1=NaN
所有数字与有NaN参与的计算的结果也会返回 NaN:
System.out.println("Operations with NaN produce NaN"); System.out.println("2 + NaN = "+ (2+Double.NaN)); System.out.println("2 - NaN = "+ (2-Double.NaN)); System.out.println("2 * NaN = "+ (2*Double.NaN)); System.out.println("2 / NaN = "+ (2/Double.NaN)); System.out.println();
上面的diam将会输出为:
OperationswithNaNproduceNaN2+NaN=NaN2-NaN=NaN2*NaN=NaN2/NaN=NaN
最后,我们知道我们不能够给 double 或者 float 指派为 null 对象类型。
作为另外一种解决方案,我们可以为 double 或者 float 指派 NaN 数值来表示丢失或者未知的值:
如下面的代码:
doublemaxValue =Double.NaN;
在本篇文章中,我们对NaN的情况进行了一些简单的讨论,同时我们也讨论了在实际的计算中可能会有哪些情况会导致产生 NaN,同时对如何进行 NaN 在 Java 中的比较和计算也提供了一些实例。
欢迎大家参与讨论。