一个浮点数或双精度浮点数中的NaN和Infinity在内存中是如何存储的?

44

据我理解,Java将浮点数存储为32位整数,并具有以下属性:

  • 第一位用于确定符号
  • 接下来的8位表示指数
  • 最后的23位用于存储小数部分

这使得没有多余的位来处理三种特殊情况:

  • NaN(非数字)
  • 正无穷大
  • 负无穷大

我猜测负零可能被用来存储其中之一。

它们在内存中实际上是如何表示的呢?


11
常量描述中写着0xfff0000000000000L=-Infinity0x7ff0000000000000L=+Infinity0x7ff8000000000000L=NaN。(这是double类型的值) - SomeJavaGuy
7
已记录在Java文档中。 - wero
6
@Lashane,谷歌搜索中的第一个链接确实是这个问题:https://www.google.com/search?q=how+are+NaN+and+infinity+stored+in+memory我认为,无论这些问题是否研究不足,它们通常都非常有用。 - Ajedi32
3
等价于Fortran的问题:https://dev59.com/73RB5IYBdhLWcg3wZWXi - Ajedi32
5
@PascalCuoq,我想说的是,仅仅因为答案可以通过阅读其他来源得到而说一个问题没有用处是不正确的。在这个问题被发布之前,搜索谷歌的人们可能必须阅读一篇维基百科关于NaN的文章才能找到答案。现在,他们可以在谷歌搜索结果的顶部找到一个完整、写得好的回答,我认为这是更好的情况。 "提问题,得答案,无干扰" - Ajedi32
显示剩余10条评论
5个回答

62

Java规定浮点数遵循IEEE 754标准

它的存储方式如下:

  • 位0:符号位
  • 位1到11:指数
  • 位12到63:小数部分

现在,我已经使用不同的双精度值执行了以下方法:

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。


3
请写出您从代码中得到的实际输出,或更新您的代码以打印您所说的内容。此外,由于当前难以快速比较,请将数字排列对齐。 - anon
你仍然没有让比较输出变得容易——而你当前给出的代码可以实现这一点。请编写该代码的实际输出,或包含将生成所提供输出的代码。 - anon
1
就像我之前说的那样,代码和格式化输出都是不言自明的。我现在遇到的问题是理解上面的评论。如果你有任何具体的问题,可以在SO上提出一个新问题,我很乐意回答。祝好! - Darshan Mehta
1
好的,我会在电脑上编辑以展示我的意思。如果您不同意,可以回滚。我没有问题;我正在努力让您改进您的答案。 - anon
1
我已经纠正了你的输出和对输出的解释。无论你的实际打印代码是什么,它都误导了你通过删除前导零位,导致你认为所有东西的符号位都被设置了。 - zwol

17

来自这里

问:如何使用IEEE 754表示零、无穷大和NaN?

答:通过将所有指数位设置为1。正无穷大 = 0x7ff0000000000000(所有指数位都是1,符号位为0,所有尾数位都是0),负无穷大 = 0xfff0000000000000(所有指数位都是1,符号位为1,所有尾数位都是0),NaN = 0x7ff8000000000000(所有指数位都是1,至少设置了一位尾数)。正零 = 所有位都是0。负零 = 所有位都是0,除了符号位为1。

还请参考Javadocs关于NAN、正无穷大和负无穷大的说明


9
这也意味着可能存在多个 NaN,它们可以互相区分(即使它们都是 NaN)。一些应用程序利用这一点来存储关于无法识别数字的性质的附加信息。 - Joey

5

维基百科所述,指数位全部设为1的指数用于识别这些数字。分数域设置为0用于识别无穷大(正或负,由符号确定),非零分数域则表示NaN值。


3

Java使用IEEE 754浮点数。

大多数数字都采用带有隐式前导1的符号-指数-尾数格式表示。

指数字段的极端值(全为0和全为1)不作为正常指数值使用。相反,它们用于表示特殊情况。

指数字段中的所有零用于表示无法在正常格式中表示的数字(包括正零和负零)。

指数字段中的所有1用于表示特殊值。如果尾数中的所有位都为零,则该值为正或负无穷大(由符号位指示)。否则,该值为NaN。


0

首先,我们必须学习数字在内存中如何表示为浮点数和双精度。

通常的数字形式为: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。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接