浮点数如何存储在内存中?
我读过,他们存储在尾数和指数的forms
我读过这个文档,但是我什么都不懂。
要理解它们是如何存储的,首先必须了解它们是什么以及它们打算处理什么样的值。
与整数不同,浮点值意味着表示非常小的值以及非常大的值。 对于正常的32位浮点值,这对应于1.175494351 * 10 ^ -38到3.40282347 * 10 ^ +38范围内的值。
显然,仅使用32位,不可能将这些数字中的每个数字都存储起来。
当涉及到表示时,可以将所有常规浮点数看作1.0到(几乎)2.0范围内的值,以2的幂次进行缩放。 所以1.0就是1.0 * 2 ^ 0 。 2.0是1.0 * 2 ^ 1 。 -5.0是-1.25 * 2 ^ 2 。
那么,需要尽可能高效地对此进行编码? 我们真的需要什么?
- expression的标志。
- 指数
- 值在1.0到(几乎)2.0的范围内。 这被称为“尾数”即有效数字。
根据IEEE-754浮点标准,这被编码如下。
- 标志是一个单一的位。
- 指数存储为无符号整数,对于32位浮点值,该字段为8位。 1表示最小的指数,“全1”是最大的。 (0和“全1”用于编码特殊值,见下文)。中间值(在32位情况下为127)代表零,这也被称为偏差 。
- 当看尾数(1.0和(几乎)2.0之间的值)时,可以看到所有可能的值以“1”开头(都是十进制和二进制表示)。 这意味着存储它是没有意义的。 其余的二进制数字存储在一个整数字段中,在32位的情况下,这个字段是23位。
除了正常的浮点值之外,还有一些特殊的值:
- 零与指数和尾数编码为零。 符号位用来表示“正零”和“负零”。 当一个操作的结果非常小的时候,零点是很有用的,但是知道操作来自哪个方向仍然很重要。
- 加和减无穷 – 用“全1”指数和零尾数字段表示。
- 不是数字(NaN) – 使用“全部1”指数和非零尾数表示。
- 非规格化数字 – 小于最小正常数字的数字。 使用零指数字段和非零尾数表示。 这些数字的特殊之处在于,精度(即一个值可以包含的数字的位数)将随着值的变小而下降,只是因为在尾数中没有空间。
最后,下面是一些具体的例子(所有值都是hex的):
- 1.0:3f800000
- -1234.0:c49a4000
- 100000000000000000000000.0:65a96816
用外行人的话来说,它本质上是二元的科学记数法 。 正式的标准(具体细节)是IEEE 754 。
typedef struct { unsigned int mantissa_low:32; unsigned int mantissa_high:20; unsigned int exponent:11; unsigned int sign:1; } tDoubleStruct; double a = 1.2; tDoubleStruct* b = reinterpret_cast<tDoubleStruct*>(&a);
如果编译器使用IEEE 754双精度(在当今大多数系统上是C双精度的默认值),如何设置内存就是一个例子。
这里是基于C的二进制forms,更好地阅读有关双精度的维基百科来理解它。
有许多不同的浮点格式。 它们中的大多数具有一些共同的特征:符号位,专用于存储指数的一些位,以及专用于存储有效位(也称为尾数)的一些位。
IEEE浮点标准试图定义可以在各种系统上实现的单一格式(或者更确切地说几种尺寸的格式)。 它还定义了可用的操作及其语义。 它很好地被捕获了,你可能遇到的大多数系统可能都使用IEEE浮点。 但其他格式仍在使用,以及不太完整的IEEE实现。 C标准为IEEE提供了可选的支持,但是并没有强制它。
尾数代表数字的最高有效位。
指数表示在尾数上执行多lessclass次以获得数字的实际值。
编码指定如何表示尾数的符号和指数符号(基本上是左移还是右移)。
您引用的文档指定了使用最广泛的IEEE编码。
我发现你引用的这篇文章相当模糊(我知道IEEE是如何漂浮的)。 我build议你尝试使用维基版本的解释。 这很清楚,有很多例子:
http://en.wikipedia.org/wiki/Single_precision和http://en.wikipedia.org/wiki/Double_precision
它是实现定义的,尽pipeIEEE-754是最常见的。
为了确保使用IEEE-754:
- 在C中,使用
#ifdef __STDC_IEC_559__
- 在C ++中,使用
std::numeric_limits<float>::is_iec559
常量