浮点数的学习契机是我要搞清楚什么是单精度浮点数,什么是双精度浮点数,一个问题,引发了一系列的深入学习。
一.基础知识
在开始正式学习之前,先聊一下计算机的存储方式,我们都知道,电子计算机的原理就是利用通电、断电(或曰高电平低电平)这两个状态来表示布尔代数中的逻辑真和逻辑假,对应的就是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代表正,因此它可能是这个样子的
我们知道,如果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。
综合上面的三个部分后,我们知道这个算式应该是:
上面我们提到过,根据指数n来移动小数点,因此上面算式的结果等价于:
0.00101000000000000000000000 = 0.00101。
注意!这是二进制,我们把0.00101转成10进制为:0.15625。这就是开头我们说的结果啦。
知识点:
- exponent 称为“指数的偏移值” ,在中文中,常常称为阶码。
- 阶码的取值范围?由于阶码由8比特组成,1比特有0或者1,因此理论上可以表示的数字范围最大是:2^8 = 256个数字。但是实际上第一个最高位是代表符号(正负的),因此去掉后的范围是2^7= -127到128之间,但是-127和128这两个有特殊用处(下面会说明),因此“指数的实际值”的取值范围就是-126-127之间。但这不是阶码的范围,阶码是“指数的实际值”+ “固定的偏移值”,因此阶码的范围是1-254。是的,阶码肯定是大于0的。
- 为什么要有“固定的偏移值”,偏移值的大小是怎么来的?很多地方的解释比较难以理解,实际上它的好处就是上一条的结论,就是偏移值的存在导致阶码肯定是大于0的,换句话讲就是我们可以用正数来表示负的指数。这个带来的好处就是计算机在处理减法运算时有局限性,采用移码的方式,可以实现计算机最舒服的数据格式,即:a - b = a + (-b),也就是计算机只会作加法。
- 这个“固定的偏移值”是怎么算出来的?IEEE754规定这个值为:
现在来定义一下规约形式的浮点数:
如果浮点数中的阶码范围在 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,称为非规约形式的浮点数。
知识点:
- 非规约形式的浮点数,它的“固定偏移值”不是127二是126。
- 非规约形式的浮点数,一般是用来表示一个数字非常接近于0时才会使用的。
- 鉴于上一条,我们有非规约形式的浮点数,一般用于小数是0.xxxx这种情况的小数部分(当然1.xxx也是可以正常使用的,只是我们约定接近于0才用非规约,所以是0.xxx)
第三条是我总结的,因为维基百科上写的晦涩难懂,我读了好多遍后的理解,有误请指出。
五. IEEE754标准-特殊值
- 如果指数是0并且尾数的小数部分是0,这个数±0(和符号位相关)
- 如果指数= 255,并且小数部分是0,这个数是正负无穷(和符号位相关)
- 如果指数 = 255,并且小数部分为非0,这个数是非数(NaN)
六.简单总结
- 我们上面第三章讲过,-127和128被用作特殊值处理,-127给了非规约形式浮点数,128给了正负无穷和NaN。
- 我们上面推导的都是单精度浮点数,双精度浮点数的规格可不是这样哦,原理一样,这里不作讲解啦。
- 一个浮点数实际上是表示了周围的一个有理数区间,不是精确值,而是代表了一个范围。
- 浮点数的计算公式为:
(-1)^S * 1.M * 2^(E-127)
七.浮点数的分布理解
理解这个的关键就是,理解浮点数的小数点是浮动的。
单精度浮点数的范围就是[1,254],那么当数字越小时,它可以移动的小数点产生的数字就越多,因此越靠近中间能表示的数字就越多。
参考文章:
感谢分享,网站设计得很棒