关于浮点数的剪不断理还乱


文章出自个人博客https://knightyun.github.io/2020/03/21/programme-float-point,转载请申明


二进制小数

谈浮点数前,先了解一些基础知识;对于整数的十进制与二进制转换不难,原理也简单就不再赘述,假如现在要进行转换的十进制数字是带有小数点的,转换方法就会稍微有点不一样了;为了使说明更浅显易懂,先来探究一下十进制小数中的奥秘;

以十进制数 3.125 为例,小数点以左为整数部分,右为小数部分,它也可以被更具体的拆解为以下形式:

这也是十进制数的特点,基数为 10,所以每一位都是与 10 的相应次方的乘积,指数也是有规律的,可以看成以小数点为对称轴,向左就是 10 的 0、1、2、3……次方递增,向右则是 10 的 -1、-2、-3……次方递减,如果换一种形式,那么在运算方面也具有对称性(乘法与除法互为逆运算),就是下面的形式:

这样,理解二进制的小数部分就容易了,已经知道整数十进制转二进制其实就是连续除以 2 取余数,那么根据上面的规律,小数部分看出逆运算,就可以总结为 连续乘 2 取整数,举例说明:

11.001 就是 3.125 的二进制小数形式,同时它也可以做如下拆解:

可以看到也是与十进制形式相对应的,只是基数从 10 换成了 2 而已;

定点数

当然,都知道机器码都是一堆 和 组成的数据,并没有小数点这个专门的符号,要表示数字 3125 还好说,但是 3.125 中间多出的这一点要怎么解决呢……一个很直接的方法就是把小数点应该在的位置焊死 -_-,比如 32 位的系统,规定小数点在 16 位和 17 位之间,那么根据 3.125 的二进制是 11.001,在 32 中的表现就是:

这就是 定点数 的规则干的事情,看着挺好,要是多用几次系统空间可能就 hold 不住了,不好之处明显就是花掉当前一半的数量级取表述小数部分,当然可以少划分几位给小数,但对小数好像不太公平,万一精度要求高呢,反过来呢对整数又不公平了,手心手背都是肉,得想办法解决才行;

浮点数

于是乎,浮点数横空出世;其实上述问题平时肯定都遇到过,比如记个帐,昨日净收入 元(@_@),肯定不想写这一堆 0 对不对(如果是真的咱愿意写 100 遍……),一般都会写 312 亿或者 元,重点就在后面这种科学计数表示法,人为了省力省纸省笔墨弄了个科学计数法,处理器也自然用上了浮点数,省空间;具体原理与表示方法后面会讲;

以 C语言为代表,其中就有浮点这一数据类型,比如单精度浮点 float(32 位),双精度浮点 double(64 位)等,可能平时也就直接声明和使用较多,没太关注底层实现的算法,其实也不太复杂,套用一种规则而已,下面开始介绍;

标准

目前关于浮点运算与表示,使用广泛的应该就是 IEEE 754(二进制浮点数算术标准)了,其主要内容如下:

该标准包含了多中位数,以 32 位为例:

总结就是:

  • 第一位为符号位 s;
  • 后 8 位为指数位 e;
  • 最后 23 位为小数位 f;

64 位的规则是:

  • 第一位是符号位 s;
  • 后 11 位是指数 e;
  • 最后 52 位是有效数字 m;

知道了这些还不能立刻套用上面的公式经行转换,还需要了解接下来的一些规定;

指数偏移值

浮点的二进制表示中指数位 e 的计算值(即转换成十进制后的值),要在实际指数值(十进制)的基础上加上一个 偏移值,标准中规定偏移值为 ,如 32 为中 e 是 8 位,所以偏移值为 127,64 位的就为 1023;所以 32 位指数实际值的范围为 ;

举个例,指数 e 的实际值为 -3,那么 32 位中加上偏移值就是 ,换算成二进制的 8 位指数位就是 ;

这种指数位偏移后的指数值,又叫做 阶码,因为科学计数法中的指数是有正负之分的,所以实际指数值加上一个正的适中偏移值,就可以使得浮点表示法中的指数位为无符号的整型(就是变成正整数),利于浮点数的比较大小,就是可以直接从浮点的二进制表示中,由高位向低位逐位进行比较(如果是负数二进制比较大小要复杂一点)。

表示方式

具体的表示方式会根据不同的情况而不同,主要有以下几种情况;

规约形式

即 e 的 8 位数字不是全部为 0 或者 1,此时 ,由于小数部分 f 的值在 0 到 1 之间,所以有效数 m 的值在 1 到 2 之间;

非规约形式

这种形式 e 的 8 位全部为 0,小数位 f 值不为 0,用于表示非常接近 0 的数,此时不再是 ,而是 ,即 m 值在 0 到 1 之间;实际上所有非规约的浮点数比规约浮点数更接近于 0;

零值

指数位 e 全为 0 的同时,小数部分(f)为 0,用来表示 (正负取决于 s 位的值);且规定最小指数位编码(e = 0 时)的实际值应该取 (本来应该是 );

无穷大

如果 e 全为 1,且 m 全为 0,则表示无穷大(Infinity,正负取决于 s 位的值);

NaN

如果 e 全为 1,且 m 不全为 0,则表示 (Not a Number,非数值类型);

综合举例

后面的例子都以 32 位为例,其它位数根据标准类推;

先来看一个十进制转浮点,规约形式的例子,比如用之前的十进制数 3.125,转换为 32 位浮点二进制格式( 开头的表示二进制数据):

转换的大致流程总结如下:

十进制小数 –> 二进制小数 –> 浮点表示法 –> 二进制浮点

再举一个二进制浮点转十进制小数例子:

精度

以 32 位单精度浮点数为例,由于分配给有效数字的位数是 23 位,而整数部分默认是 1,它的位置就不用留了,所以小数部分就可以独占 23 位,在加上默认的一个整数位就是 24 位了,同理,64 位双精度浮点数的有效数就是 53 位(52+1),再进行一下算术运算:

上面的算式表示二进制下的这么多位数的实际值,对应到十进制中有多少位;结果表明,单精度浮点可以保证 7 位十进制的有效数字,双精度的则可以保证 15 位;

“浮”的原因

取名为浮点,那么到底“浮”在了什么地方,与定点数相比的优势又是什么的看来,其实其转换操作很类似于十进制中的科学计数法,而科学计数法的出现,就是为了实现能简短地书写较大的数,比如写作 ,就可以避免在 1 后面写那令人抓狂的 20 个 0 了;

同理,二进制中如果用定点数表示小数,那么 32 位的话就最多到 32 位有效数字,而用这种类似科学技术的浮点表示法的话,指数能表示到 100 以上,也就是 100 多位了,相信现在的 100 位系统也是稀有物种了吧;因此,浮点数有效的扩大了能表示的数据范围,科学计数法减少了书写量,浮点表示则是节省了存储空间;

另外也是由于科学计数本身的特性,以及指数偏移值,也就是 阶码 的应用,小数点也就不再像之前一样固定,具体位置会根据指数的大小最终“漂浮”到不同的位置,甚至到那遥远的地方……


技术文章推送
手机、电脑实用软件分享
关于浮点数的剪不断理还乱

来源:瑝琦

声明:本站部分文章及图片转载于互联网,内容版权归原作者所有,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2020年2月18日
下一篇 2020年2月18日

相关推荐