IEEE 754 浮点表示是否在浪费内存?

Is IEEE 754 floating point representation wasting memory?

我一直以为一个double类型的变量可以存储2^64个不同的小数值。 (每个位可以有 1 或 0 作为值,因此有 2^64 个不同的值)。

最近我才知道NaN(不是数字)有一个表示,其中指数部分是11111111111,尾数部分是任何非零值。 相反,如果指数部分是 11111111111 并且有效数字部分是 111111 ……(52 次),那么表示形式是 NaN 吗?

这难道不能让我们表示 2^52 个不同的数字吗? 2^52 是一个巨大的数字。那我们不是在浪费宝贵的space吗?

IEEE-754 浮点格式在设计时考虑到了高效的硬件实现。所有特殊输入操作数都可以通过仅检查指数字段来检测,指数字段是 all-0(零和非正规数)或 all-1(无穷大和 NaN)。因此,对于双精度,只需要一个 11 位比较器,并且可以在处理器周期的一小部分内执行检查。

为无穷大和 NaN 保留 2048 种可能的指数编码之一并不是特别浪费。请注意,IEEE-754 使用两种不同类型的 NaN:信号 NaN 或 SNaN,在遇到时触发异常,而完全 NaN 或 QNaN 则通过计算简单地传播,直到它们出现在人类可消费的最终结果中。尾数字段的最高有效位区分两种 NaN:对于 SNaN 清零,对于 QNaN 置位。

此外,IEEE-754 支持但不要求NaN 的概念"payload",即具有系统或用户定义含义的多个 NaN 编码。例如,"PowerPC Numerics" (Apple 1994) 为 Macintosh 系统指定 NaN 的小数字段的第 8 到第 15 个最高有效位包含一个 NaN 代码,它指示 NaN 的不同来源,例如sqrt() 的非零负数,log() 的负数,反三角函数的无效参数,例如 asin()。如 "Apple Numerics Manual, Second Edition"(Apple 1988)中所述,Apple II 引入的 SANE(标准 Apple 数值环境)已经使用了这个概念。

C 和 C++ 标准通过 math.h / cmath 提供标准函数 nan(),可用于以实现定义的方式从字符串参数构造 NaN 有效负载。有关简要说明,请参见 here.

示例

换句话说,它可能在存储上浪费了 0.048%,但在更简单的芯片设计和电源效率上节省了十倍。我觉得很划算。

这在实践中意味着最大的可表示数是 ~

179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

359538626972463140000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

所以这些“浪费”的值无论如何都不会那么有用。