IEEE 754 && 浮点数学习
🏮

IEEE 754 && 浮点数学习

Tags
IEEE
Published
January 20, 2022
Author
Eironn Walker

IEEE 754 && 浮点数学习

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

一.基础知识

在开始正式学习之前,先聊一下计算机的存储方式,我们都知道,电子计算机的原理就是利用通电、断电(或曰高电平低电平)这两个状态来表示布尔代数中的逻辑真和逻辑假,对应的就是1和0,因此我们说计算机的最小单位是bit(比特/位),能够表示0或者1。
形如下面的样子:
notion image
那如何表示形如1.134441的数据呢?于是有了一个标准,也就是IEEE754。
在学习这个标准之前,先简单介绍一下科学计数法,因为这个标准是借助于这种记数方式的。

二.科学计数法

我们在表示一个数的时候,如:327.849,可以用科学计数法来表示:
+3.27849 × 10^2
由三部分组成:
+是符号
中的2是指数
3.27849是有效数
指数部分,根据正负,我们可以知道把327.849向左还是向右移动几个小数点。

.名次对照

这部分知识名词有点多,因此写了下面的对照表,看不懂的话可以阅读完全部文章后再对照。
名词
解释
sign/符号位
标识正负的符号位,0正,1负
指数/阶码
这两个概念经常被混淆。在本文中,指数指的是真实的指数值,阶码指的是偏移后的指数值。即:指数 + 偏移量 = 阶码
fraction/尾数
fraction和尾数也容易被混淆。在IEEE754标准中,fraction仅仅存入的是小数点右边的值。除了0之外,IEEEE754中有效数是1.xxx 或者0.xxx,fraction存入的部分仅仅是xxx。因此尾数应该指的是完整的有效数。而fraction是去掉了1.或者0.之后的xxx部分。
指数偏移值
为了让指数存入到计算机中的值全部是正数,因此出现了这个偏移量。指数 + 偏移量 = 阶码
特殊值
正/负无穷,非数值(NaN)

.IEEE754标准

名词
解释
规约形式的浮点数
尾数是1.xxx
非规约形式的浮点数
尾数是0.xx,一般表示极小的浮点数,为了处理突然式下溢出
正负零
阶码是0,指数是-127,尾数是0
特殊值
正/负无穷,非数值(NaN)
 

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

由于浮点数分为规约形式的浮点数、非规约形式的浮点数、零和特殊值。我们先不考虑非规约形式的浮点数和零和特殊值,只考虑规约形式的浮点数,下面讲的是规约形式的单精度浮点数(最常用的)。
在维基百科中,对浮点数的表示方法为:
Value(值) = sign(符号位)× exponent(阶码)×fraction(分数值/小数)
对应下面这张图片。
notion image
上面的图是表示的0.15625(十进制)这个小数,在计算机中存储的样子。
然后我们通过解释这张图来学习IEEE754标准。
sign这个就是符号位,0代表正,1代表负。上图等价于下面的式子
(因为是2进制,所以是2的n次方而不是10的;二进制的有效数只要不是0,那么肯定是以1开头的数,而且规约形式的浮点是定义为1开头的)
我们知道,如果n是正,那么小数点向右移动n位,如果n为负,那么小数点向左移动n位。
01111100(二进制阶码) = 124(10进制阶码)。但是这个值不能直接带入到2的n次方中使用,因为指数这个值实际上等于指数真正的值加上一个偏移量后,得到的阶码值,来存储的(为什么要加偏移量后面会解释)。
比如说,实际指数是17(10进制),那么存入到磁盘中的值,需要加上偏移量127(10进制),即144(十进制阶码),把这个值转成二进制存入到上面图片的exponent部分。
那么根据这个规则我们可以算出实际的指数是124(阶码)-127(偏移量)=-3(真实的指数)。
fraction要格外注意,图中01000000000000000000000直接转换为10进制为2097152,在移动小数点的时候不能使用十进制,而需要用二进制去移动,因为在IEEE754标准中,针对的是二进制的数。
另外,所有的非0有效数,都可以表示为1.xxx × 2的n方,所以为了节省存储,上面图片的fraction部分是省略了1的,我们整合起来就是:1.01000000000000000000000。
综合上面的三个部分后,我们知道这个算式应该是:
上面我们提到过,根据指数n来移动小数点,因此上面算式的结果等价于:
0.00101000000000000000000000 = 0.00101。
注意!这是二进制,我们把0.00101转成10进制为:0.15625。这就是开头我们说的结果啦。

知识点:

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

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

如果浮点数的指数部分的阶码是0,小数部分非零,那么这个浮点数将被称为非规约形式的浮点数。一般是某个数字相当接近零时才会使用非规约型式来表示。
非规约形式的浮点数,指数偏移值比规约形式浮点数少1,即126。
因此非规约形式的浮点数的指数真实值是-126(阶码0),和规约形式的浮点数阶码1(指数真实值-126)相等。但是两者的尾数不同,一个0.xxx,一个1.xxx
为何非规约形式的浮点数的偏移值是-126而不是127?没有深入去了解,可能是为了和规约浮点数的数间距保持一致?都是,也就是实现渐进式下溢出。
知识点:
  1. 非规约形式的浮点数,它的“固定偏移值”不是127而是126。
  1. 非规约形式的浮点数,一般是用来表示一个数字非常接近于0时才会使用的。
  1. 鉴于上一条,我们有非规约形式的浮点数,一般用于小数是0.xxxx这种情况的小数部分(当然1.xxx也是可以正常使用的,只是我们约定接近于0才用非规约,所以是0.xxx)

. IEEE754标准-特殊值

特殊值指的是正负无穷和非数(NaN)
  1. 如果阶码全是1=255(真实指数是128),并且小数部分是0,这个数是正负无穷(和符号位相关)
  1. 如果阶码全是1=255(真实指数是128),并且小数部分为非0,这个数是非数(NaN)

八.正负零

如果阶码是0(真实的指数是-127)并且尾数的小数部分是0,这个数±0(和符号位相关)

.简单总结

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

.浮点数的分布理解

理解这个的关键就是,理解浮点数的小数点是浮动的,浮点数不是一个点,而是代表了一个范围。
单精度浮点数的指数范围就是[-127,128],那么当数字绝对值越小时,它可以移动的小数点产生的数字就越多,因此越靠近中间能表示的数字就越多。
notion image
参考文章: