浮点数的有效数字位数
过去有一种很普遍的说法是单精度浮点数的有效数字是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.322log210≈3.322对于单精度浮点数,第N位10进制有效数字后还有24−N×log21024 - N \times log_21024−N×log210个2进制位可用。如果说单精度浮点数能保证N位有效数字,意味着N位后刚好不再有足够的2进制位数能区分10种不同情况。可以很容看出,这个N应该是让N×log210N \times log_210N×log210不大于24的最大的整数。也就是N=⌊24log210⌋=7N = \lfloor {24 \over log_210} \rfloor = 7N=⌊log21024⌋=7最终,我们得出N是7。(⌊x⌋\lfloor x \rfloor⌊x⌋表示对xxx向下取整)
至此为止,我们知道了该如何计算有限位数的2进制有效数字能保证的10进制有效数字位数。比如我们还可以计算53位2进制有效数字的双精度浮点数可以保证的10进制位数是⌊53log210⌋=15\lfloor {53 \over log_210} \rfloor = 15⌊log21053⌋=15
正篇到此结束。
后记
这里开始,我不再保证能尽量说人话。
换个角度
因为有Mlog210=log22Mlog210=log102M{M \over log_210} = {log_22^M \over log_210} = log_{10}2^Mlog210M=log210log22M=log102M所以单精度浮点能保证的有效数字位数等价于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.322log210≈3.322。很显然2log210=102^{log_210} = 102log210=10
浮点数的有效数字位数相关推荐
- float型浮点数的精确位数
浮点数只能表示形如 x × 2 y ( x , y ∈ Z ) x\times2^y(x,y\in Z) x×2y(x,y∈Z)的有理数.所以对于绝大多数的实数,浮点数都无法精确表示,而只能利用自己有 ...
- MySQL对浮点数设置保留位数
MySQL对浮点数设置保留位数 文章目录 MySQL对浮点数设置保留位数 FORMAT ROUND TRUNCATE CONVERT(类型转换函数) 有如下几个方法可以设置查询结果保留的位数 FORM ...
- python控制浮点数输出的位数
有的时候需要控制python中的浮点数输出的位数,一般有三种方法: ① 使用round函数,用法为:round( x [, n] ),x为浮点数,n为保留的小数位数参数是可选的如果不写那么默认不保留小 ...
- R中控制输出数值的小数点位数round,和有效数字位数signif
小数点位数round round(x, n) # x为数字.n为保留的位置 示例 > x=3.1415926 > round(x,3) [1] 3.14 如果位数太长,需要科学计数法时,用 ...
- 【C++】使用setprecision控制输出流显示浮点数的有效数字个数
setprecision的头文件为:#include <iomanip> 会自动四舍五入- setprecision(n)表示显示n个有效数字 和fixed连用可以控制小数点后面输出的位数 ...
- C++规定输出的数据的有效数字位数
文章目录 前言 一.有效数字是什么? 二.代码实现 1.源代码 2.使用示例 总结 前言 控制有效数字输出并非意味着保留小数点后就位数字,对于初学者而言,对后者可能接触较多,而对于前者,可能接触甚少. ...
- C++ 浮点数保留有效数字
保留6位有效数字 #include<iostream> #include<iomanip> //对应setprecison #include<vector> #in ...
- tecplot有效数字位数
在contour--->details--->labels 中,最下面有一个Number Format
- Python:浮点数保留小数位数的方法整理
示例 print('%.2f' % 1.255) # 1.25print('{:.2f}'.format(1.2635)) # 1.26print(format(1.235, '.2f')) # 1. ...
最新文章
- 贴吧html标签,html标签3(转载)
- 什么时候需要用到RCC_APB2Periph_AFIO--复用IO时钟的使用
- 谷歌浏览器 关闭 提示恢复网页功能_最强浏览器又更新喽!
- Eclipse最新版 Neon已发布
- 指定特定的内容为首页
- spring(4)面向切面的Spring(AOP)
- 产品认知:产品经理如何锻炼产品思维?
- 使用 npm script 的钩子
- Spring Boot(十三):整合Redis哨兵,集群模式实践
- Android 之 ProgressDialog用法介绍
- php排列组合1004无标题,PHP的排列组合有关问题
- 软件测试面试题(每日一刷)
- 使用Word2010直接编辑、发布博客→博客园cnblogs
- ehcache 实现缓存共享
- php 修改文件的权限_php修改文件权限
- mysql建表语句注释_MySQL建表语句+添加注释
- 智能门锁主流品牌有哪些?选购门锁时要注重产品的哪些特性?
- 一个Android菜鸡的2020之旅
- 计算机系统应用 莫军,Configuration tool for ARINC 653 operating systems
- mds is damaged
热门文章
- WebService之Axis2 Log4j 2.x 漏洞升级教程
- 文件夹显示无法访问、拒绝访问需要权限的解决方法
- only regular white space (\r, \n, \t) is allowed between tokens
- 关于springboot使用getServletContext().getRealPath(““)获取的是tomcat的临时缓存文件问题
- 阿里EasyExcel读写excel文件的基本使用
- c primer plus电子版_2019年全国大学生英语竞赛C类(NECCS)决赛试题+答案解析
- phpstudy的安装
- Fedora安装Hadoop
- /static/fonts/SIMYOU.TTF’ 字体
- 3ds Max科研作图(三)