首页 > 代码库 > 有趣的NaN类型

有趣的NaN类型

  在学习Java集合的时候遇到了Float.isNaN(float)函数,点进去一看就不理解了,函数实现如下:

public static boolean isNaN(float v) {        return (v != v);    }

  float的v怎么会不等于自身呢?以下是关于这个函数的描述:

   /**     * Returns {@code true} if the specified number is a     * Not-a-Number (NaN) value, {@code false} otherwise.     *     * @param   v   the value to be tested.     * @return  {@code true} if the argument is NaN;     *          {@code false} otherwise.     */
isNaN()描述:返回一个 Boolean 值,指明提供的值是否是保留值 NaN (不是数字)。语法:isNaN(numvalue)numvalue 参数是要检查是否为 NaN 的值。说明:如果值是 NaN, 那么 isNaN 函数返回 true ,否则返回 false 。

  从上述描述可以知道,这个函数判断一个float参数是不是NaN(Not a Number),即不是一个数字,那么什么是NaN,什么情况下会出现NaN呢?


定义:  

  NaN(Not a Number,非数)是计算机科学中数值数据类型的一个值,表示未定义或不可表示的值。常在浮点数运算中使用。首次引入NaN的是1985年的IEEE 754浮点数标准。

会返回NaN的运算:

  • 操作数中至少有一个是 NaN 的运算
  • 未定义操作
    • 下列除法运算:0/0、∞/∞、∞/−∞、−∞/∞、−∞/−∞
    • 下列乘法运算:0×∞、0×-∞
    • 下列加法运算:∞ + (−∞)、(−∞) + ∞
    • 下列减法运算:∞ - ∞、(−∞) - (−∞)
  • 产生复数结果的实数运算。例如:
    • 对负数进行开方运算
    • 对负数进行对数运算
    • 对比-1小或比+1大的数进行反正弦或反余弦运算

 

Java中的NaN:

  Java中的Double和Float中都有isNaN函数,判断一个数是不是NaN,其实现都是通过上述 v != v 的方式,因为NaN是唯一与自己不相等的值,NaN与任何值都不相等。有些操作会使isNaN返回True,例如:

System.out.println(Float.isNaN(0.0f / 0.0f));System.out.println(Double.isNaN(Math.sqrt(-1)));

Double的NaN定义:

   /**     * A constant holding a Not-a-Number (NaN) value of type     * {@code double}. It is equivalent to the value returned by     * {@code Double.longBitsToDouble(0x7ff8000000000000L)}.     */    public static final double NaN = 0.0d / 0.0;

  以上定义了一个常量型的NaN,它的效果和Double.longBitsToDouble(0x7ff8000000000000L)的返回值是一样的,我们可以看看Double.longBitsToDouble中的定义:

If the argument is any value in the range 0x7ff0000000000001L through 0x7fffffffffffffffL or in the range 0xfff0000000000001L through 0xffffffffffffffffL, the result is a NaN. No IEEE 754 floating-point operation provided by Java can distinguish between two NaN values of the same type with different bit patterns.

  如上可知,二进制的0x7ff0000000000001L~0x7fffffffffffffffL 和 0xfff0000000000001L~0xffffffffffffffffL 之间的数值是被定义成NaN类型,类似正无穷大和负无穷大,但又有区别。在Float中也类似。

  总之,在实际数值计算的过程中可能会出现一些非法的操作,导致产生了非法的数值,比如说除零,通过NaN来表示这样一个非数值,NaN与任何浮点数(包括自身)的比较结果都为假,即 (NaN ≠ x) = false,这是NaN独有的特性,所以可以使用与自己相比来确定当前数值是不是一个正常的数。

简单测试:

  @Test    public void NanTest() {        Float f1 = new Float(-1.0 / 0.0);        Float f2 = new Float(0.0 / 0.0);        Double f3 = Math.sqrt(-1);        // returns true if this Float value is a Not-a-Number(NaN), else false        System.out.println(f1 + " = " + f1.isNaN());        System.out.println(f2 + " = " + f2.isNaN());        System.out.println(f3 + " = " + f3.isNaN());        System.out.println(Double.isNaN(Double.longBitsToDouble(0x7ff0000000000011L)));    }

 

参考资料:

Java isNan how it works?
Float.NaN == Float.NaN
Java.lang.Float.isNaN() Method
http://zh.wikipedia.org/wiki/NaN
IEEE 754

 

有趣的NaN类型