技术专栏

IEEE754标准: 二, float类型的取值范围

2018-07-16  本文已影响2386人  等夏天再见啦

这是"IEEE754标准系列"的第二篇文章. 主要讨论32位浮点数 (或者说float类型) 的取值范围到底是如何计算出来的.

关于此问题, 如果去网上搜索的话, 会发现一些不同版本的答案, 其中有一些是正确的, 而另一些则属于误传. 至于正确的取值范围是怎么计算出来的, 大多数文章也没有给出具体的算法, 或给出的算法是错误的.

这篇文章主要是基于IEEE754的维基百科整理出来的, 对float类型的取值范围和具体算法做了详细的解释.

一. float类型的取值范围

这里先直接给出维基上的取值范围

可见float类型, 或者说32位浮点数的取值范围是±1.18×10−38 to ±3.4×1038, 准确的说是

[-3.4*10^38, -1.18*10^-38] ∪ [1.18*10^-38, 3.4 * 10^38]


二. 计算方法: 前置概念

接下来会详细介绍这个范围是怎么计算出来的, 不过在介绍具体的计算方法前, 必须先了解一些概念.

只有了解了这些概念, 才能真正的理解浮点数的取值范围是如何计算出来的. 而理解这些概念之前, 请务必确定你已经对IEEE754的基础概念和浮点数在内存中的存储方式有所了解, 也可以参考本系列的第一篇文章: IEEE754标准: 一, float类型在内存中的存储方式

概念一: subnormal number

根据IEEE754的规定, 按照尾数位隐藏的整数部分是1.还是0. 可以将浮点数划分为两类

下面以32位浮点数为例来解释这些概念.

normal number: 尾数位隐藏的整数部分是1.的数, 叫做normal number, 即正常的数

一般来说, 我们遇到的都是normal number

比如20.5在内存中表示为: 0  1000 0011  0100 1000 0000 0000 000

其中尾数部分(即上面的加粗部分), 去掉后面补的零之后为: 01001

这其实表示尾数是: 1.01001, 因为前面省略了整数部分1.

subnormal number: 尾数位隐藏的整数部分为0.的数, 叫做sunormal number, 也叫作denormal number, 即低于正常的数

之所以引入subnormal number这个概念, 是为了在浮点数下溢时, 可以逐位的损失精度, 以尽可能精确的表达0附近的极小数(如0.0000001)

为了表示subnormal number, IEEE754规定: 如果将指数位全部填充为0, 则表示这个数是个subnormal number

即以32位float为例, 当你看到类似于 * 00000000 *********************** 这样内存状态的数时, (即指数位全部为0的数), 就应该知道, 这是个subnormal number, 此时这个数的尾数位隐藏的整数不是1.  而是0.

概念二: non-number

和subnormal number类似, IEEE754对于指数位全为1的状态也做了特殊规定:

当指数位全部被1填充, 即指数位表示的值为255时, 用于表示这个浮点数处在一种非正常数(non-number)的状态: 即这个数可能是±infinity或NaN. (Infinity和NaN是两个特殊值, 分别表示无穷和Not a Number)

The biased-exponent field is filled with all 1 bits to indicate either infinity or an invalid result of a computation.

三. 计算方法

在了解了上面两个概念之后, 再看计算方法就很简单了.

如上所述, IEEE754规定, 当指数位全部为0或者全部为1时, 用于表示两种特殊状态的数: subnormal number 和 non-number, 所以现在可以得到如下示意图, 以32位单精度浮点数为例:

这就是理解单精度浮点数取值范围的关键: 当我们讨论浮点数的取值范围时, 实际上讨论的是: normal number (上图中绿色部分)的范围.

可以看出, 32位浮点数的指数其实是无法取到-127和128的, 因为用于表示-127的0000 0000被用来表示subnormal number了, 而用于表示128的1111 1111被用来表示non-number了. 所以实际上32位浮点数的指数部分只能取到只能取到[-126, 127]

下面来看看尾数: 对于normal number, 尾数前隐藏的整数部分始终保持1.

所以尾数(含隐藏的整数部分)表示值的范围其实是 [1.00...00, 1.11...11],

这个二进制数, 约等于十进制的[1, 2), 因为1.11..11非常逼近十进制的2

好啦, 现在我们知道, 对于32位flaot而言: 尾数(含隐藏的整数部分)的可取值为: [1 ,2), 指数位可取值[-126, 127]

且浮点数可正可负, 所以32位float的取值范围是:

[-2 * 2^127, -1 * 2^-126] ∪ [1 * 2^-126, 2 * 2^127]

约等于:

[-3.4*10^38, -1.18*10^-38] ∪ [1.18*10^-38, 3.4 * 10^38]

浮点数的取值范围即这样计算出来的.

下面是 32位float浮点数的取值范围示意图, 可以参照此图更好的理解一下

x轴代表以2为底的n次幂(即内存中的指数部分), y轴代表尾数(含隐藏的整数部分1.)

坐标系中任意一点(x, y)就代表一个浮点数,

这一点到x轴, y轴所围成的矩形的面积即这个浮点数的值 (即浮点数的值 = 尾数(含隐藏的整数部分) * 以2为底的n次幂, 例子可以参见下面的一张图)

蓝色部分表示浮点数取值范围, 即用于表示浮点数的坐标点只能出现在坐标轴中的蓝色区域.

坐标点表示一个浮点数

橙色部分的面积表示该浮点数的值.

这就是32位浮点数取值范围的计算方法.

下一篇将详细介绍为什么说32位浮点数的精度是"7位有效数", 7位有效数又到底指的是什么...

上一篇下一篇

猜你喜欢

热点阅读