据我理解,Java将浮点数存储为32位整数,并具有以下属性:
- 第一位用于确定符号
- 接下来的8位表示指数
- 最后的23位用于存储小数部分
这使得没有多余的位来处理三种特殊情况:
- NaN(非数字)
- 正无穷大
- 负无穷大
我猜测负零可能被用来存储其中之一。
它们在内存中实际上是如何表示的呢?
Java规定浮点数遵循IEEE 754标准。
它的存储方式如下:
现在,我已经使用不同的双精度值执行了以下方法:
public static void print(double d){
System.out.println(Long.toBinaryString(Double.doubleToRawLongBits(d)));
}
我使用这些值执行:
print(Double.NaN);
print(Double.NEGATIVE_INFINITY);
print(Double.POSITIVE_INFINITY);
print(-Double.MAX_VALUE);
print(Double.MAX_VALUE);
对于上述值,获得以下输出(为了可读性进行格式化):
NaN: 0111111111111000000000000000000000000000000000000000000000000000
-Inf: 1111111111110000000000000000000000000000000000000000000000000000
+Inf: 0111111111110000000000000000000000000000000000000000000000000000
-Max: 1111111111101111111111111111111111111111111111111111111111111111
+Max: 0111111111101111111111111111111111111111111111111111111111111111
维基百科解释,当指数字段为全1时,该数字是无穷大还是非数(NaN)取决于尾数。无穷大的尾数全0;NaN的尾数至少有一个1。正号位对无穷大仍具有其正常意义,但对NaN没有意义。Java中的Double.NaN
是一种特殊值,将被解释为NaN,但还有253−3个其他值也被视为NaN。
来自这里:
问:如何使用IEEE 754表示零、无穷大和NaN?
答:通过将所有指数位设置为1。正无穷大 = 0x7ff0000000000000(所有指数位都是1,符号位为0,所有尾数位都是0),负无穷大 = 0xfff0000000000000(所有指数位都是1,符号位为1,所有尾数位都是0),NaN = 0x7ff8000000000000(所有指数位都是1,至少设置了一位尾数)。正零 = 所有位都是0。负零 = 所有位都是0,除了符号位为1。
还请参考Javadocs关于NAN、正无穷大和负无穷大的说明。
Java使用IEEE 754浮点数。
大多数数字都采用带有隐式前导1的符号-指数-尾数格式表示。
指数字段的极端值(全为0和全为1)不作为正常指数值使用。相反,它们用于表示特殊情况。
指数字段中的所有零用于表示无法在正常格式中表示的数字(包括正零和负零)。
指数字段中的所有1用于表示特殊值。如果尾数中的所有位都为零,则该值为正或负无穷大(由符号位指示)。否则,该值为NaN。
首先,我们必须学习数字在内存中如何表示为浮点数和双精度。
通常的数字形式为:1.M * 2^e。
(其中M被称为尾数,e是超过127的指数)
浮点数中
最高有效位(Most significant bit)用作符号位,位号从23到31用于以超过127的形式表示的指数值,而位号从0到30用于存储尾数。
双精度中
最高有效位(Most significant bit)用作符号位,位号从52到63用于以超过127的形式表示的指数值,而位号从0到51用于存储尾数。
因此,现在我们可以理解在浮点数或双精度中NaN,Infinity的表示。
NaN(非数字)
在NaN的表示中,所有指数位都是1,尾数位可以是任何值,无论是浮点还是十进制都不重要。
Infinity(无限大)
在表示无穷大的时候,所有指数位都是1,尾数位都是0,而它是浮点数还是十进制数并不重要。 正无穷大的表示与上述相同,但符号位为0,而负无穷大的表示也与上述相同,但符号位为1。
0xfff0000000000000L=-Infinity
,0x7ff0000000000000L=+Infinity
和0x7ff8000000000000L=NaN
。(这是double类型的值) - SomeJavaGuy