原始浮点数和双精度浮点数支持多少位小数?

17
我读到过double可以存储15位数字,而float只能存储7位数字。我的问题是,这些数字是支持的小数位数还是数字中的总位数?

1
更准确地说,这些是表示所有浮点数(在范围[0,1]内)所需的十进制位数。说浮点表示“支持”或“存储”N个数字可能会导致人们认为浮点可以表示所有小数到该精度,而实际上它们通常甚至不能表示所有小数到第一位的精度。当然,显然,比该精度更高的任何数字都无法被浮点数精确表示。 - eerorika
4个回答

20

如果你使用 IEEE-754 浮点运算的架构(大多数架构都是这样),那么类型 float 对应于单精度,而类型 double 对应于双精度,如标准中所描述。

让我们来看一些数字:

单精度:

32 位用于表示数字,其中24 位用于尾数。这意味着最低有效位(LSB)相对于 MSB 具有2^(-24)的相对值,它是“隐藏的1”,并且不会被表示。因此,对于固定的指数,可表示的最小值为指数的10^(-7.22)倍。这意味着对于以基数指数表示的数字(3.141592653589 E 25),只有“7.22”个十进制数字是有效的,在实践中至少有7个小数总是正确的。

双精度:

64 位用于表示数字,其中53 位用于尾数。按照同样的推理,将2^(-53)表示为10的幂会得到10^(-15.95),这意味着至少15个小数总是正确的。


LSB相对于MSB的值为2^(-23),而不是2^(-24)。 - gnasher729
实际上,“真正的” MSB 被隐藏起来,不在尾数中表示,因为它总是 1(由于浮点数)。因此,在尾数中表示的 MSB 相对于指数具有 2^(-1) 的值,而 LSB 具有 2^(-24) 的值。这个考虑对于计算正确的小数位数非常重要。当然,如果你考虑到在尾数中表示的 MSB 的相对值,那么你是正确的。 - Samuel Navarro Lou

7

从左到右计数,无论小数点在哪里,这些都是“有效数字”的总数。超过这些数字的位数,精度就无法保证。

您列出的计数是基于10进制表示的。


5
有用于每种浮点类型所支持的小数位数的宏。 GCC文档 解释了它们是什么以及它们的意义:
FLT_DIG 这是float数据类型的十进制数字精度。从技术上讲,如果p和b分别为表示的精度和基数,则十进制精度q是最大的十进制数字(即q个10进制数字),使得具有q个基本 b位数字的任何浮点数都可以四舍五入为具有p个基本b位数字的浮点数,然后再次返回,而不会更改q个十进制数字。 该宏的值应至少为6,以满足ISO C。
DBL_DIG LDBL_DIG 这些与FLT_DIG类似,但对应于double和long double数据类型,它们的宏的值应至少为10。
在gcc 4.9.2和clang 3.5.0上,这些宏分别为6和15。

3
这些数字是一个数字中包含的有效位数,而非总位数(虽然你可能不需要所有这些位数,但它们仍然存在)。同一类型的尾数始终包含相同数量的位数,因此每个数字在十进制位数方面都包含相同数量的有效“数字”。你不能存储比尾数能容纳的位数更多的位数。
“支持”的数字数量要多得多,例如,float通常支持最多38个十进制位数,double支持最多308个十进制位数,但大多数这些数字是无意义的(即“未知”)。
尽管在技术上,这是错误的,因为float和double没有像我上面假设的那样普遍定义的大小(它们是实现定义的)。此外,存储大小未必与中间结果的大小相同。
C++标准非常勉强地定义任何基本类型,几乎将所有内容都留给了实现。浮点类型也不例外:
有三种浮点类型:float、double和long double。类型double提供至少与float一样的精度,类型long double提供至少与double一样的精度。类型float的值集是类型double的值集的子集;类型double的值集是类型long double的值集的子集。浮点类型的值表示是实现定义的。
当然,在实践中,浮点数(通常)遵循IEEE 754标准,float的宽度为32位,double的宽度为64位(存储在内存中,某些著名的主流架构的寄存器具有更高的精度)。
这相当于分别拥有24个和53个尾数,或7个和15个完整十进制位数。

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