c科学计数法转化成浮点数_算法工程师应该了解的浮点数知识

本文介绍了浮点数在计算机中的表示方式,特别是科学计数法如何转换为二进制浮点数,讨论了IEEE 754标准中的有效数字M和指数E的存储规则,包括特殊情况如全0和全1的位模式。还提到了浮点数的精度问题,以及在比较和相加时需要注意的精度损失。
摘要由CSDN通过智能技术生成

“强基固本,行稳致远”,科学研究离不开理论基础,人工智能学科更是需要数学、物理、神经科学等基础学科提供有力支撑,为了紧扣时代脉搏,我们推出“强基固本”专栏,讲解AI领域的基础知识,为你的科研学习提供助力,夯实理论基础,提升原始创新能力,敬请关注。

作者: 知乎-Dounm

地址:https://www.zhihu.com/people/niu-chong

作为一个算法工程师,工作中经常会用到浮点数相关的知识,比如要对比两个浮点数的误差,再比如混合精度在 float 和 half 之间做变换。 因此,有必要了解一些浮点数相关的知识。

01

浮点数的表示

根据国际标准IEEE 754,任意二进制浮点数都可表示为abb6c5f0-6c48-eb11-8da9-e4434bdf6706.svg

  • b2b6c5f0-6c48-eb11-8da9-e4434bdf6706.svg :符号位。 b6b6c5f0-6c48-eb11-8da9-e4434bdf6706.svg 代表正数, bab6c5f0-6c48-eb11-8da9-e4434bdf6706.svg 代表负数。

  • bfb6c5f0-6c48-eb11-8da9-e4434bdf6706.svg :有效数字,大于1,小于2

  • c5b6c5f0-6c48-eb11-8da9-e4434bdf6706.svg :指数位

举例:

  • dcb6c5f0-6c48-eb11-8da9-e4434bdf6706.svg 的二进制是 e4b6c5f0-6c48-eb11-8da9-e4434bdf6706.svg ,则 e8b6c5f0-6c48-eb11-8da9-e4434bdf6706.svg

  • ebb6c5f0-6c48-eb11-8da9-e4434bdf6706.svg 的二进制是 f3b6c5f0-6c48-eb11-8da9-e4434bdf6706.svg ,则 f6b6c5f0-6c48-eb11-8da9-e4434bdf6706.svg

  • fab6c5f0-6c48-eb11-8da9-e4434bdf6706.svg 的二进制是 02b7c5f0-6c48-eb11-8da9-e4434bdf6706.svg ,则 07b7c5f0-6c48-eb11-8da9-e4434bdf6706.svg

02

浮点数的存储

首先我们要注意区分浮点数的「表示值」(下标 0db7c5f0-6c48-eb11-8da9-e4434bdf6706.svg )和「存储值」(下标 10b7c5f0-6c48-eb11-8da9-e4434bdf6706.svg )。

上一节的例子中, 14b7c5f0-6c48-eb11-8da9-e4434bdf6706.svg 的值都是表示值,但真正把这些浮点数存储在内存中时,具体存储的值并不等同与表示的值。

这一些都是因为 IEEE 754 对 16b7c5f0-6c48-eb11-8da9-e4434bdf6706.svg 和 1db7c5f0-6c48-eb11-8da9-e4434bdf6706.svg 的存储还有些特殊规定。

针对有效数字 M

对于有效数字 16b7c5f0-6c48-eb11-8da9-e4434bdf6706.svg , IEEE 规定其表示值必须满足 2bb7c5f0-6c48-eb11-8da9-e4434bdf6706.svg ,所以 2fb7c5f0-6c48-eb11-8da9-e4434bdf6706.svg 总是1.xxxxx的形式。

但 IEEE 规定存储 16b7c5f0-6c48-eb11-8da9-e4434bdf6706.svg 时可以不存第一位的1,所以 37b7c5f0-6c48-eb11-8da9-e4434bdf6706.svg 只保存xxxxx,即 3bb7c5f0-6c48-eb11-8da9-e4434bdf6706.svg ,这样就可以节省一位有效数字。

所以,前例中的 3fb7c5f0-6c48-eb11-8da9-e4434bdf6706.svg ,但实际只用存储 44b7c5f0-6c48-eb11-8da9-e4434bdf6706.svg 。

针对指数 E

对于指数E ,因为 E 是unsigned int,所以如果 E 有 8bit(Float),那么取值为0~255;如果E 有11bit(Double),取值为0~2047。

但科学计数法的 E 可以为负数,所以 IEEE 规定 49b7c5f0-6c48-eb11-8da9-e4434bdf6706.svg 。

对于8bit E (float),Exponent Bias 是 4bb7c5f0-6c48-eb11-8da9-e4434bdf6706.svg ;对于11bit E (double),Exponent Bias 是 4eb7c5f0-6c48-eb11-8da9-e4434bdf6706.svg 。

因此,前例中 51b7c5f0-6c48-eb11-8da9-e4434bdf6706.svg ,那如果用 Float 数据类型来保存该数字,真正要保存在内存里的其实是 56b7c5f0-6c48-eb11-8da9-e4434bdf6706.svg

除此之外,还有两种特殊情况:

  • 5ab7c5f0-6c48-eb11-8da9-e4434bdf6706.svg 的 bits 全为0

以 float 数据类型为例,若按照默认规则,则 5db7c5f0-6c48-eb11-8da9-e4434bdf6706.svg ;但实际上,对于此种情况,特殊规定 61b7c5f0-6c48-eb11-8da9-e4434bdf6706.svg 。

因此, 65b7c5f0-6c48-eb11-8da9-e4434bdf6706.svg 和 69b7c5f0-6c48-eb11-8da9-e4434bdf6706.svg 对应的 6cb7c5f0-6c48-eb11-8da9-e4434bdf6706.svg 一样。但区别在于, 65b7c5f0-6c48-eb11-8da9-e4434bdf6706.svg 对应的有效数字的表示值 72b7c5f0-6c48-eb11-8da9-e4434bdf6706.svg ,即 0.xxxxx(与默认规定不同);而 69b7c5f0-6c48-eb11-8da9-e4434bdf6706.svg 对应的有效数字的表示值 78b7c5f0-6c48-eb11-8da9-e4434bdf6706.svg 1.xxxxx(与默认规定相同)。

为什么要对 65b7c5f0-6c48-eb11-8da9-e4434bdf6706.svg 采用特殊规定呢?
因为采用默认规定的话,我们能表示的最小数字 7fb7c5f0-6c48-eb11-8da9-e4434bdf6706.svg ,该num必然大于 82b7c5f0-6c48-eb11-8da9-e4434bdf6706.svg 。
而如果采用上述特殊规定, 86b7c5f0-6c48-eb11-8da9-e4434bdf6706.svg ,则可以表示更小的数字,即 Subnormal Numbers。

  • 5ab7c5f0-6c48-eb11-8da9-e4434bdf6706.svg 的 bits 全为1
    如果此时 37b7c5f0-6c48-eb11-8da9-e4434bdf6706.svg 的 bits 全是0,则表示正负无穷大inf;否则就是NaN

03

总结

如果以存储值来表示任意浮点数的话(除去前面提到的两种特殊情况),其默认公式如下:90b7c5f0-6c48-eb11-8da9-e4434bdf6706.svg

常见浮点数据类型

9f0b091a4dc0aa64fb132e9bbfcda131.png

对于任意浮点数来说,其最高位存的是sign;最低位存储Fraction bit。

关于表格最右侧的十进制有效数字,因为 95b7c5f0-6c48-eb11-8da9-e4434bdf6706.svg ,所以二进制精度如果是24位的话,那么十进制有效数字约7位。因此,对于 float16这种浮点数来说,其十进制有效数字就特别小,如果 debug 时看到两个 half 的区别特别大,也不用特别惊慌,这是正常现象 _(:3」∠)_

浮点数的一些其它相关

  • 如果两个浮点数相加会怎样?

更小的数字会被shifted right来保证exponent一致,方便加法。因此,该更小的数字会损失部分的significand精度(即round-off error,Floating-point arithmetic - Wikipedia)

  • 浮点数能否精确表示 97b7c5f0-6c48-eb11-8da9-e4434bdf6706.svg ?

因为浮点数的存储也是基于二进制的,因此对于 97b7c5f0-6c48-eb11-8da9-e4434bdf6706.svg 这种无法用二进制精确表示的数字,实际上在计算机里存储的都是临近值(同理还有 9fb7c5f0-6c48-eb11-8da9-e4434bdf6706.svg 等 )。

float a = 0.1;    cout << a << endl; // 输出0.1,因为cout的默认输出精度不高,所以会roundup为0.1cout.precision(10);   cout << a << endl; // 输出0.1000000015
  • 如何判断两个浮点数相等?

因为浮点数会有精度损失,因此我们通常并不会用 == 来判断两个浮点数相等,而是判断两者 diff 是否足够小,小到一定程度就认为两个浮点数相等。

此处可以参考 numpy.isclose(...) 的实现,通过公式 absolute(a - b) <= (atol + rtol * absolute(b)) 来判断两个浮点数是否相等。

Refer

[1] IEEE 754-1985 - Wikipedia

https://en.wikipedia.org/wiki/IEEE_754-1985

[2] 浮点数的二进制表示

http://www.ruanyifeng.com/blog/2010/06/ieee_floating-point_representation.html

本文目的在于学术交流,并不代表本公众号赞同其观点或对其内容真实性负责,版权归原作者所有,如有侵权请告知删除。

0405172d58b5067ffe122c867dc2e4e3.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值