一些浮点精度和数值限制问题

Some floating point precision and numeric limits question

本文关键字:问题 精度      更新时间:2023-10-16

我知道有很多这样的问题,但我找不到答案。请在投票前阅读以关闭(:

  • 根据PC ASM:
数字协处理器有八个浮点寄存器。每个寄存器保存80位数据。浮点数始终存储为 80 位这些寄存器中的扩展精度数字。

这怎么可能,当sizeof显示不同的东西时。例如,在 x64 体系结构上,double的大小为 8,这与 80 位相去甚远。

  • std::numeric_limits< long double >::max()为什么给我1.18973e+4932?!这是呜�如果这不是获取最大浮点数的方法,那么为什么要编译它,甚至更多 - 为什么这会返回一个值。

  • 这是什么意思:

双精度幅度的范围可以从大约 10^−308 到 10^308 

这些是巨大的数字,你不能将它们存储到 8B 甚至 16B 中(这是扩展精度,只有 128 位)?

显然,我错过了一些东西。实际上,很明显,很多事情。

1) sizeof是内存中的大小,而不是寄存器中的大小。 sizeof以字节为单位,因此 8 字节 = 64 位。 当在内存中计算双精度值时(在此体系结构上),它们将获得额外的 16 位,以进行更精确的中间计算。 当该值被复制回内存时,额外的 16 位将丢失。

2)为什么你认为long double不会上升到1.18973e+4932?

3)为什么不能在8字节中存储10 ^308? 我只需要 13 位:4 位存储 10 位,9 位存储 308 位。

  1. double不是英特尔协处理器 80 位浮点数,而是 IEEE 754 64 位浮点数。使用sizeof(double),您将获得后者的大小。

  2. 这是获得long double最大值的正确方法,所以你的问题毫无意义。

  3. 您可能忽略了浮点数不是确切的数字。 10^308 不存储 308 位数字,只存储大约 19 位数字。

FPU 使用的空间大小和内存中用于表示double的空间量是两回事。IEEE 754(可能大多数体系结构都使用)指定 32 位单精度和 64 位双精度数字,这就是sizeof(double)为您提供 8 个字节的原因。英特尔 x86 使用 80 位在内部执行浮点数学运算。

std::numeric_limits< long double >::max()为您提供了正确的long double大小,通常为 80 位。如果您想要 64 位双精度的最大大小,则应将其用作模板参数。

对于关于范围的问题,为什么您认为不能将它们存储在 8 个字节中?它们确实适合,而你缺少的是,在范围的极端处,有一些数字无法表示(例如,指数接近 308,有许多整数根本无法表示)。

另请参阅 http://floating-point-gui.de/有关浮点的信息。

计算机上的浮点数根据IEEE 754-2008表示。

它定义了几种格式,其中包括
二进制32 = 单精度,
binary64 = 双精度和
binary128 = 四倍精度是最常见的。
http://en.wikipedia.org/wiki/IEEE_754-2008#Basic_formats

双精度数字有 52 位用于数字,用于提供

精度,10 位用于指数,用于给出数字的大小。
所以双精度是 1.xxx(52 个二进制数字)* 2 ^ 指数(10 个二进制数字,所以最多 2^10=1024)

和 2^1024 = 1,79 * 10^308
这就是为什么这是您可以存储在双精度中的最大值。

使用四精度数字时,它们是 112 位精度和 14 位指数,因此最大指数是 16384。

当 2^16384 给出 1,18 * 10^4932 时,您会看到您的C++测试是完全正确的,并且在 x64 上,您的双精度实际上存储在四精度数字中。