IEEE 754标准和浮点数学习


浮点数的学习契机是我要搞清楚什么是单精度浮点数,什么是双精度浮点数,一个问题,引发了一系列的深入学习。

一.基础知识

在开始正式学习之前,先聊一下计算机的存储方式,我们都知道,电子计算机的原理就是利用通电、断电(或曰高电平低电平)这两个状态来表示布尔代数中的逻辑真和逻辑假,对应的就是1和0,因此我们说计算机的最小单位是bit(比特/位),能够表示0或者1。

形如下面的样子:

那如何表示形如1.134441的数据呢?于是有了一个标准,也就是IEEE754。

在学习这个标准之前,先简单介绍一下科学计数法,因为这个标准是借助于这种记数方式的。

二.科学计数法

我们在表示一个数的时候,如:327.849,可以用科学计数法来表示:

+3.27849 × 10^2

由三部分组成:

+是符号

10^2中的2是指数

3.27849是有效数

指数部分,根据正负,我们可以知道把327.849向左还是向右移动几个小数点。

三.IEEE754标准-规约形式的浮点数

由于浮点数分为规约形式的浮点数、非规约形式的浮点数、还有特殊值。我们先不考虑非规约形式的浮点数和特殊值,只考虑规约形式的浮点数,下面讲的是规约形式的单精度浮点数(最常用的),最后讲另外两种浮点数。

在维基百科中,对浮点数的表示方法为:

Value(值) = sign(符号位)× exponent(指数)×fraction(分数值/小数)

对应下面这张图片。

上面的图是表示的0.15625(十进制)这个小数,在计算机中存储的样子。

然后我们通过解释这张图来学习IEEE754标准。

因为sign的0代表正,因此它可能是这个样子的

2^n × 1.001011

我们知道,如果n=10,那么小数点向右移动10位,如果n=-10,那么小数点向左移动10位。

但是如果要根据上面的公式计算出图片中的这个值,需要按照一定规则转换(先不用去考虑为何这样的规则,按照规则转换即可,下面介绍)。

sign这个就是符号位,0代表正,1代表负。

exponent = 01111100 = 124(10进制)。但是这个值不能直接带入到2的n次方中使用,因为指数这个值实际上等于指数真正的值加上一个偏移量后,得到的偏移量,来存储的(为什么要加偏移量后面会解释)。比如说,实际指数是17(10进制),那么存入到磁盘中的值,需要加上偏移量127(10进制),即144(十进制),把这个值转成二进制存入到上面图片的exponent部分。那么根据这个规则我们可以算出实际的指数是124-127=-3(十进制)。

fraction要格外注意,图中01000000000000000000000直接转换为10进制为2097152,这是不对的(而且不能现在转10进制),因为在IEEE754标准中,01000000000000000000000代表的是小数部分:因为所有的数,在使用科学计数法表示的时候,都可以表示为1.xxx × 10的x方,所以上面图片的fraction部分是省略了1的,我们整合起来就是:1.01000000000000000000000。

综合上面的三个部分后,我们知道这个算式应该是:

2^{-3} \times 1.01000000000000000000000 \\

上面我们提到过,根据指数n来移动小数点,因此上面算式的结果等价于:

0.00101000000000000000000000 = 0.00101。

注意!这是二进制,我们把0.00101转成10进制为:0.15625。这就是开头我们说的结果啦。

知识点:
  1. exponent 称为“指数的偏移值” ,在中文中,常常称为阶码。
  2. 阶码的取值范围?由于阶码由8比特组成,1比特有0或者1,因此理论上可以表示的数字范围最大是:2^8 = 256个数字。但是实际上第一个最高位是代表符号(正负的),因此去掉后的范围是2^7= -127到128之间,但是-127和128这两个有特殊用处(下面会说明),因此“指数的实际值”的取值范围就是-126-127之间。但这不是阶码的范围,阶码是“指数的实际值”+ “固定的偏移值”,因此阶码的范围是1-254。是的,阶码肯定是大于0的。
  3. 为什么要有“固定的偏移值”,偏移值的大小是怎么来的?很多地方的解释比较难以理解,实际上它的好处就是上一条的结论,就是偏移值的存在导致阶码肯定是大于0的,换句话讲就是我们可以用正数来表示负的指数。这个带来的好处就是计算机在处理减法运算时有局限性,采用移码的方式,可以实现计算机最舒服的数据格式,即:a - b = a + (-b),也就是计算机只会作加法。
  4. 这个“固定的偏移值”是怎么算出来的?IEEE754规定这个值为:
2^{e-1} -1 \\e代表的exponent的位数,单精度浮点数上图可知,就是8

现在来定义一下规约形式的浮点数:

如果浮点数中的阶码范围在 0 < exponent < 2^e -2 之间,即上面说的[1,254]之间(指的是单精度浮点数哦),并且在科学计数法下,小数部分是以1开头的,级1.xxx。那么这个浮点数被称为规约形式的浮点数。

四.IEEE754标准-非规约形式的浮点数

我们上一章讲过,阶码的范围是[1,254]之间,而非规约形式的浮点数,就是阶码为0时。

上一章提到的-127用作特殊处理了,实际上用在这里了,我们想:-127+固定偏移量127 = 0。反过来讲,因为非规约形式的浮点数的阶码肯定为0,那么0-127 = -127,也就是非规约形式的浮点数的指数永远是-127,这实际是错误的!因为IEEE754规定,非规约形式的浮点数,它的“固定偏移值”是126,因此非规约形式的浮点数的指数的实际值 = -126 和规约形式的浮点数的指数的实际值1一样,都是-126。

我们先说结论,非规约形式的浮点数为:阶码为0,小数部分(fraction)不为0,称为非规约形式的浮点数。

知识点:
  1. 非规约形式的浮点数,它的“固定偏移值”不是127二是126。
  2. 非规约形式的浮点数,一般是用来表示一个数字非常接近于0时才会使用的。
  3. 鉴于上一条,我们有非规约形式的浮点数,一般用于小数是0.xxxx这种情况的小数部分(当然1.xxx也是可以正常使用的,只是我们约定接近于0才用非规约,所以是0.xxx)

第三条是我总结的,因为维基百科上写的晦涩难懂,我读了好多遍后的理解,有误请指出。

五. IEEE754标准-特殊值

  1. 如果指数是0并且尾数的小数部分是0,这个数±0(和符号位相关)
  2. 如果指数= 255,并且小数部分是0,这个数是正负无穷(和符号位相关)
  3. 如果指数 = 255,并且小数部分为非0,这个数是非数(NaN)

六.简单总结

  1. 我们上面第三章讲过,-127和128被用作特殊值处理,-127给了非规约形式浮点数,128给了正负无穷和NaN。
  2. 我们上面推导的都是单精度浮点数,双精度浮点数的规格可不是这样哦,原理一样,这里不作讲解啦。
  3. 一个浮点数实际上是表示了周围的一个有理数区间,不是精确值,而是代表了一个范围。
  4. 浮点数的计算公式为:
(-1)^S * 1.M * 2^(E-127)

七.浮点数的分布理解

理解这个的关键就是,理解浮点数的小数点是浮动的。

单精度浮点数的范围就是[1,254],那么当数字越小时,它可以移动的小数点产生的数字就越多,因此越靠近中间能表示的数字就越多。

参考文章:

维基百科-IEEE754

深入理解浮点数有效位,浮点数分布

知乎-计算机中的浮点数在数轴上分布均匀吗?

声明:Eironn's Blog|版权所有,违者必究|如未注明,均为原创|本网站采用BY-NC-SA协议进行授权

转载:转载请注明原文链接 - IEEE 754标准和浮点数学习


Java开发,同时会一些旁门左道。