过去有一种很普遍的说法是单精度浮点数的有效数字是6到7位。同时也有一个很普遍的问题就是:“6到7位是什么意思?到底是6位还是7位?”。现在似乎主流认知已经变成了单精度浮点数的有效数字就是7位。事实究竟是怎么样的?

先说结论

单精度浮点数可以保证7位10进制有效数字。如果一个数字用10进制表示时有效数字位数大于等于7位,那么用单精度浮点数记录的话,能确保至少正确记录前7位
为什么说“至少”?比如,4294967296有10位10进制有效数字,但只有1位2进制有效数字(2进制表示是1后面32个0)。我们可以验证单精度浮点数是可以正确记录所有10位有效数字的。但上面只是特殊情况,对于随便给出的一个数,只有第7位和之前的有效数字是能确信正确的。

凭什么说就是7位,为什么不是6位、8位?

最简单的2进制的情况

首先,我假设我们知道一个单精度浮点数种有24位2进制的有效数字(不知道的同学,请先自行搜索IEEE 754)。很显然,对于有24位或者以上2进制有效数字的数,单精度浮点数能保证前24位。

再看看16进制

我们知道16进制的1位对应2进制的4位(不知道的同学,……姑且4位2进制数刚好有16种不同的情况)。2进制的24位刚好对应16进制的6位,也就是能保证6位16进制的有效数字。
但是假设我们只有23位2进制有效数字的话,那么我们就只能保证5位了。

接下来我们更具体地看一下。假设有16进制数87654321(16)87654321_{(16)}87654321(16)​,我们可以写成8.7654321(16)×1678.7654321_{(16)} \times 16^78.7654321(16)​×167。2进制的话,可以写成1000.0111′0110′0101′0100′0011′0010′0001(2)×2281000.0111'0110'0101'0100'0011'0010'0001_{(2)} \times 2^{28}1000.0111′0110′0101′0100′0011′0010′0001(2)​×228如果我们只有24位2进制有效数字,则后面一部分有效数字无法记录,就成了1000.0111′0110′0101′0100′0011(2)×2281000.0111'0110'0101'0100'0011_{(2)} \times 2^{28}1000.0111′0110′0101′0100′0011(2)​×228也就是8.76543(16)×1678.76543_{(16)} \times 16^78.76543(16)​×167。如果再减少1位2进制有效数字的话1000.0111′0110′0101′0100′001(2)×2281000.0111'0110'0101'0100'001_{(2)} \times 2^{28}1000.0111′0110′0101′0100′001(2)​×228我们将只有3位2进制数001能用来表示最后1位16进制有效数字。我们知道,3位2进制数只有8种不同情况,无法区分16进制1位数的16种情况。更具体地,比如这样我们无法区分8.76543(16)×1678.76543_{(16)} \times 16^78.76543(16)​×167和8.76542(16)×1678.76542_{(16)} \times 16^78.76542(16)​×167,因为它们的最后一位都会被表示成001。

可以看到,无法保证有效数字的某一位,意味着我们没办法区分这一位可能出现的所有情况。反过来,如果说我们能保证某一位,说明去掉这一位之前所用掉的2进制有效数字位数后,我们还能剩下足够的2进制位数来区分这一位可能出现的所有情况

回过头看前面我们用1位2进制表示10位10进制有效数字的情况。1位2进制有效数字有可能表示出10位的10进制有效数字,但是要能区分出10位10进制数的所有情况,我们还是需要更多的2进制位。

万恶的10进制

如果能见到神的话,我一定要问他人为什么要长10个指头而不是8个——如果不能是16个的话……

下面我们要解决的问题是:去掉10进制某一位之前用掉的2进制有效数字后,我们怎么计算还剩下多少2进制位数。

高能预警:这将不是个整数

我们知道3位2进制数有8种不同情况,4位2进制数有16种不同情况。而每位有10种情况的10进制要对应2进制的多少位?咱们姑且直接用这结果log210≈3.322log_210 \approx 3.322log2​10≈3.322对于单精度浮点数,第N位10进制有效数字后还有24−N×log21024 - N \times log_21024−N×log2​10个2进制位可用。如果说单精度浮点数能保证N位有效数字,意味着N位后刚好不再有足够的2进制位数能区分10种不同情况。可以很容看出,这个N应该是让N×log210N \times log_210N×log2​10不大于24的最大的整数。也就是N=⌊24log210⌋=7N = \lfloor {24 \over log_210} \rfloor = 7N=⌊log2​1024​⌋=7最终,我们得出N是7。(⌊x⌋\lfloor x \rfloor⌊x⌋表示对xxx向下取整)

至此为止,我们知道了该如何计算有限位数的2进制有效数字能保证的10进制有效数字位数。比如我们还可以计算53位2进制有效数字的双精度浮点数可以保证的10进制位数是⌊53log210⌋=15\lfloor {53 \over log_210} \rfloor = 15⌊log2​1053​⌋=15

正篇到此结束。

后记

这里开始,我不再保证能尽量说人话。

换个角度

因为有Mlog210=log22Mlog210=log102M{M \over log_210} = {log_22^M \over log_210} = log_{10}2^Mlog2​10M​=log2​10log2​2M​=log10​2M所以单精度浮点能保证的有效数字位数等价于2242^{24}224(也就是16777216)去掉最高位后的位数。很多人会说这个就是单精度浮点数能表示7位有效数字的原因。从这个角度解释也是可以的,但是直接这么下结论跳过的步骤太多了。而且从这角度解释铺垫起来会麻烦很多。

“至少”的问题

为了方便,我们看16进制。

这个问题用24位有效数字不太好说,我们看23位。上面说了2进制23位是可以确保16进制的5位的。但是1.2345678(16)×167=1.0010′0011′0100′0101′0110′0111′1000(2)×2281.2345678_{(16)} \times 16^7 = 1.0010'0011'0100'0101'0110'0111'1000_{(2)} \times 2^{28}1.2345678(16)​×167=1.0010′0011′0100′0101′0110′0111′1000(2)​×228保留23位有效数字是1.0010′0011′0100′0101′0110′01(2)×228=1.234564×1671.0010'0011'0100'0101'0110'01_{(2)} \times 2^{28} = 1.234564 \times 16^71.0010′0011′0100′0101′0110′01(2)​×228=1.234564×167好像出来了6位。应该很容易注意到,这里16进制的最高位只占用了2进制的1位,所以后面多了3位可用。

所以计算第N位还能使用的2进制位数,不是简单的用总的2进制位数,减去(N−1)×4(N - 1) \times 4(N−1)×4。而应该是减去第1位使用的2进制位数后,再减(N−2)×4(N - 2) \times 4(N−2)×4。

你可能觉得这样我们前面的方法就不准确的了,其实不然。因为我们要计算的是位数最少的情况,而这样只会让位数变多。

除了最开始提到的特殊情况,这是单精度浮点数正确表示超过7位10进制有效数字的更普遍的一种特殊情况。当然,这样最多只能表示出8位。

非整数的位数是什么鬼

拿10进制来讲,我们可以说第N位和10N10^N10N是对应的。比如我们想把3往左移动2位,就可以3×102=3003 \times 10^2 = 3003×102=300。于是往左移动半位也就是3×100.5=310≈9.4873 \times 10^{0.5} = 3 \sqrt {10} \approx 9.4873×100.5=310​≈9.487
前面10进制1位对应2进制log210≈3.322log_210 \approx 3.322log2​10≈3.322。很显然2log210=102^{log_210} = 102log2​10=10

浮点数的有效数字位数相关推荐

  1. float型浮点数的精确位数

    浮点数只能表示形如 x × 2 y ( x , y ∈ Z ) x\times2^y(x,y\in Z) x×2y(x,y∈Z)的有理数.所以对于绝大多数的实数,浮点数都无法精确表示,而只能利用自己有 ...

  2. MySQL对浮点数设置保留位数

    MySQL对浮点数设置保留位数 文章目录 MySQL对浮点数设置保留位数 FORMAT ROUND TRUNCATE CONVERT(类型转换函数) 有如下几个方法可以设置查询结果保留的位数 FORM ...

  3. python控制浮点数输出的位数

    有的时候需要控制python中的浮点数输出的位数,一般有三种方法: ① 使用round函数,用法为:round( x [, n] ),x为浮点数,n为保留的小数位数参数是可选的如果不写那么默认不保留小 ...

  4. R中控制输出数值的小数点位数round,和有效数字位数signif

    小数点位数round round(x, n) # x为数字.n为保留的位置 示例 > x=3.1415926 > round(x,3) [1] 3.14 如果位数太长,需要科学计数法时,用 ...

  5. 【C++】使用setprecision控制输出流显示浮点数的有效数字个数

    setprecision的头文件为:#include <iomanip> 会自动四舍五入- setprecision(n)表示显示n个有效数字 和fixed连用可以控制小数点后面输出的位数 ...

  6. C++规定输出的数据的有效数字位数

    文章目录 前言 一.有效数字是什么? 二.代码实现 1.源代码 2.使用示例 总结 前言 控制有效数字输出并非意味着保留小数点后就位数字,对于初学者而言,对后者可能接触较多,而对于前者,可能接触甚少. ...

  7. C++ 浮点数保留有效数字

    保留6位有效数字 #include<iostream> #include<iomanip> //对应setprecison #include<vector> #in ...

  8. tecplot有效数字位数

    在contour--->details--->labels 中,最下面有一个Number Format

  9. Python:浮点数保留小数位数的方法整理

    示例 print('%.2f' % 1.255) # 1.25print('{:.2f}'.format(1.2635)) # 1.26print(format(1.235, '.2f')) # 1. ...

最新文章

  1. 贴吧html标签,html标签3(转载)
  2. 什么时候需要用到RCC_APB2Periph_AFIO--复用IO时钟的使用
  3. 谷歌浏览器 关闭 提示恢复网页功能_最强浏览器又更新喽!
  4. Eclipse最新版 Neon已发布
  5. 指定特定的内容为首页
  6. spring(4)面向切面的Spring(AOP)
  7. 产品认知:产品经理如何锻炼产品思维?
  8. 使用 npm script 的钩子
  9. Spring Boot(十三):整合Redis哨兵,集群模式实践
  10. Android 之 ProgressDialog用法介绍
  11. php排列组合1004无标题,PHP的排列组合有关问题
  12. 软件测试面试题(每日一刷)
  13. 使用Word2010直接编辑、发布博客→博客园cnblogs
  14. ehcache 实现缓存共享
  15. php 修改文件的权限_php修改文件权限
  16. mysql建表语句注释_MySQL建表语句+添加注释
  17. 智能门锁主流品牌有哪些?选购门锁时要注重产品的哪些特性?
  18. 一个Android菜鸡的2020之旅
  19. 计算机系统应用 莫军,Configuration tool for ARINC 653 operating systems
  20. mds is damaged

热门文章

  1. WebService之Axis2 Log4j 2.x 漏洞升级教程
  2. 文件夹显示无法访问、拒绝访问需要权限的解决方法
  3. only regular white space (\r, \n, \t) is allowed between tokens
  4. 关于springboot使用getServletContext().getRealPath(““)获取的是tomcat的临时缓存文件问题
  5. 阿里EasyExcel读写excel文件的基本使用
  6. c primer plus电子版_2019年全国大学生英语竞赛C类(NECCS)决赛试题+答案解析
  7. phpstudy的安装
  8. Fedora安装Hadoop
  9. /static/fonts/SIMYOU.TTF’ 字体
  10. 3ds Max科研作图(三)