这并不像通常想象的那么简单。对于尾数的准确性,一般有两个值:
给定一个十进制表示的值,如果从十进制转换为选定的二进制格式并返回(使用默认舍入),可以保证保留多少个十进制数字。
给定一个二进制格式的值,如果将该值转换为十进制格式并返回到原始二进制格式(同样,使用默认舍入),需要多少个十进制数字才能保持原始值不变。
在这两种情况下,十进制表示形式都被视为独立于指数,没有前导零和尾随零(例如,0.0123e4、1.23e2、1.2300e2、123、123.0、123000.000e-3 都是 3 位数字)。
对于 32 位二进制浮点数,这两个大小分别是 6 和 9 位十进制数字。在 C
<float.h>
; 中,它们是 FLT_DIG
和 FLT_DECIMAL_DIG
。 (这很奇怪,32 位浮点数在所有数字中保留了 7 位小数,但也有例外。)
在 C++ 中,分别查看 std::numeric_limits<float>::digits10
和 std::numeric_limits<float>::max_digits10
。
对于 64 位二进制浮点数,分别为 15 和 17(分别为
DBL_DIG
和 DBL_DECIMAL_DIG
;和 std::numeric_limits<double>::{digits10, max_digits10}
)。
它们的通用公式(thx2 @MarkDickinson)
${format}_DIG
(数字10):floor((p-1)*log10(2))
${format}_DECIMAL_DIG
(最大位数10):ceil(1+p*log10(2))
其中
p
是尾数中的位数(包括标准化 IEEE754 情况的隐藏位数)。
此外,在 C++ numeric Limits 页面上进行一些数学解释的评论:
标准 32 位 IEEE 754 浮点类型有 24 位小数部分(写入 23 位,隐含 1 位),这可能表明它可以表示 7 位小数(24 * std::log10(2) 为 7.22) ,但相对舍入误差不均匀,并且某些具有 7 个小数位的浮点值无法在转换为 32 位浮点数并返回后继续存在:最小的正例是 8.589973e9,在往返后变为 8.589974e9。这些舍入误差在表示中不能超过一位,digits10 计算为 (24-1)*std::log10(2),即 6.92。向下舍入结果为值 6。
在注释中查找 16 位和 128 位浮点数的值(但请参阅下文了解实际的 128 位浮点数)。
对于指数,这更简单,因为每个边界值(标准化的最小值、非标准化的最小值、表示的最大值)都是精确的,并且可以轻松获取和打印。
@PaulPanzer 建议
numpy.finfo
。它给出了这些值中的第一个({format}_DIG);也许这就是您搜索的东西:
>>> numpy.finfo(numpy.float16).precision
3
>>> numpy.finfo(numpy.float32).precision
6
>>> numpy.finfo(numpy.float64).precision
15
>>> numpy.finfo(numpy.float128).precision
18
但是,在大多数系统上(我的系统是 x86-84 上的 Ubuntu 18.04),该值对于 float128 来说是令人困惑的;它实际上适用于具有 64 位有效数的 80 位 x86“扩展”浮点数;真正的 IEEE754 float128 有 112 个有效位,因此实际值约为 33,但 numpy 在此名称下提供了另一种类型。详情请参见这里:一般来说,float128是numpy中的一个错觉。
UPD3:您提到
float8
- IEEE754 集中没有这种类型。人们可以想象这种类型用于某些完全特定的目的,但其范围对于任何通用用途来说都太窄了。
为了保持简单。
一般随着数值大小的增大或减小,精度的小数位数也分别增大或减小
一般来说,
Data-Type | Precision
----------------------
float16 | 3 to 4
float32 | 6 to 9
float64 | 15 to 17
float128 | 18 to 34
如果你明白了别忘了给答案点赞
按位属性:
float16
:1 个符号位,5 个指数位,10 位有效数(小数部分)。
float32
:1 个符号位、8 个指数位和 23 位有效数(小数部分)。
float64
:1 个符号位、11 个指数位和 52 个小数位。
float128
:1 个符号位、15 个指数位和 112 个小数位。