美文网首页技术专栏
IEEE754标准: 二, float类型的取值范围

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

作者: 等夏天再见啦 | 来源:发表于2018-07-16 22:15 被阅读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位有效数又到底指的是什么...

    相关文章

      网友评论

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

        本文链接:https://www.haomeiwen.com/subject/vtkipftx.html