深入浅出IEEE浮点数表示法
使用二进制定点表示浮点数十分麻烦,且由于有些浮点数的二进制不能精确表示,只能添加小数位数不断近似,使得位数开销极大。20世纪70年代已经有一些计算机厂家推出了自己的浮点数表示标准,但并不统一,于是在1985年IEEE 742标准被提出,作为目前国际浮点数的表示标准。
IEEE 742标准规定了一个浮点数表示公式:V = (-1)^s * M * 2^E
怎么理解这个公式?
其实这里有一个知识点:浮点数是用科学计数法来表示的。
比如十进制数25.125
25.125_{(D)} = 11001.001_{B} = 1.1001001 * 2^4
你也可以把它表示成0.11001001 * 2^5,11.001001 * 2^3, 110.01001 * 2^2,11100100.1 * 2^{-3}等等,实际上浮点数的得名也是源自于它的点位漂浮不定的情况,在实际应用中我们采用IEEE 标准,用科学计数法统一表示这些浮点数。
回头看公式,其中V(Value)表示浮点数的十进制值;
S(Sign)符号位表示浮点数的正符号,取1为负,0为正;上例显然是正数, S = 0。
注意,面对这个符号位要摆脱之前整数补码取反加1求负的思想,实际上求浮点数的负值只要偏转一个符号位就行了。
M(Mantissa)表示尾数,表示 二进制浮点数 科学计数法表示形式 下的小数部分; 上例中M = 1.1001001
E (Exponent) 表示阶码,是一个有符号数,表示 二进制浮点数 科学计数法表示形式 的2次幂的值,上例中 E = 4
怎么把数装进计算机的二进制位?
IEEE 提供了浮点数的32位和64位表示形式:
![]()
这里除了符号位外又看到两个变量exp 和 frac 。
这两个参数的作用是什么?这里又要开始讲IEEE标准,制定IEEE标准的这帮人根据exp的值分了三类情况:规格化,非规格化,特殊值情况,我们先主讲规格化的情况。
规格化
即exp的位模式既不全为0也不全为1的情况,该情况下IEEE二进制数对应到科学计数法表示要通过如下公式:
E = exp - bias
M = 1 + frac
exp是exponent,即指数,注意别和阶码E混淆,exp是一个无符号整数,而E是有符号整数;
frac是fraction, 即M去掉整数部分后的小数字段, 注意规格化表示下尾数的第一位一定是1,正如科学计数法下非0数表示的第一位一定非0的情况。
其中bias 是一个偏置值,和之前2.3用于保证整数向0舍入的bias不一样,这个bias是用于浮点数计算时能对齐两数的阶码使用的。这一部分我并不是了解的很清楚,目前要记住E是一个移码,参考:
bias 的取值是 bias = 2^{n-1} - 1 ,其中 n 是exp的数据位数,单精度下bias 值为
127(n = 8), 双精度下为1023(n = 11)。单精度情况下,阶码E的有符号表示范围为
-127 ~ +128,但是-127 和 128 在规格化里是没被用来表示的,原因是在IEEE标准中这两个数分别被用来规定了非规格化和特殊值的情况,也即单精度的规格化阶码exp范围是 00000001(-126)-11111110(127) , 之后讨论。注意,看exp不能按正常的二进制转十进制的思维转成十进制,需要减去偏差。
单精度情况exp和E对照:
exp(B) exp(D) E 0000 0000 (非规格化) 0 -126(非规格化情况E = 1 - bias) 0000 0001 1 -126 … 1111 1110 254 127 1111 1111 (特殊值) 255 -- 规格化情况的公式变为:
V = \begin{cases} (-1)^s * (1 + frac)*2^{exp - 127},float\\\ (-1)^s * (1 + frac)*2^{exp - 1023},double\end{cases}
按照规格表示,我们得到了25.125D(即1.1001001 * 2^4)的单精度表示方法:
1_{(s,1位)} 10000011_{(exp,8位)} 10010010000000000000000_{(fra,23位)}
注意,在实际的位表示中开头1被省略掉了(即implied leading 1, 隐含的1开头表示),用以获得一个额外的尾数位以提高精度。
非规格化
阶码域全为0时,表示的值就是非规格化的,非规格数可以用来表示0及其他一些非常小的数,注意+0.0和-0.0在浮点数中是同时存在的,仅有符号位的不同。非规格化中M和E的公式定义为:
M = frac
E = 1- bias
非规格化的尾数是0开头的,故M代表的就是小数部分,至于E 为什么等于 1-bias会比较费解,其实这里的1是对非规格化数没有隐含的1的补偿,其有益于最大非规格化数到最小规格化数的平滑转变。
另外,值比较小的规格化的数在更低位数的机器中可能成为非规格化数。我们知道,增大尾数位有益于提高浮点数的表示精度从而得到更大的规格化值,而增大指数为有益于提高浮点数的表示范围得到更小更精确的规格化值,我们可以试想下列情况:
设阶码位为k, 尾数位为n,偏置量bias
32位环境下的某小数0.001953的二进制表示形式为:
0_{(s,1位)}01110101_{(exp,8位)} 11111111111101111001110_{(fra,32位)}
其计数表示为1.1111111111110111100111 * 2^{-10}
放到k = 4,n = 3,bias = 7的机器环境中表示为:
0_{(s,1位)}0000_{(exp,4位)} 001_{(fra,3位)}
E = 1 - 7 = -6, M = 0.001 ,故0.001953在该环境下表示为0.001* 2^{-6}
(0.000000001_{B},显然是1/512的近似结果,具体看CSAPP图2-35参考),
若要让小数点到达1前,阶码值需要到-9,即规格化表示是1.0 * 2^{-9},可是该环境下的阶码E范围为 -6 ~ 7,显然超出了取值范围,E取最小值也无法满足开头是1的规格化条件,只能表示成非规格形式。
另外可见,如果表示的浮点数的计数表示超过了E的最大范围,就会导致溢出,值变为+\infty。比如上述环境中256.0的计数表示为 1.0* 2^8, 用4个指数位已经不够表示了(E = 14(1110) - 7 = 7 < 8(1111)),于是全1溢出。
特殊值
特殊值包括正无穷,负无穷和NaN(即不是一个数,Not a Number), 在阶码全为1的时候出现,其中当小数位全为0时,s=1表示负无穷,s=0表示正无穷,如果小数位不全为数就是NaN, 它们的用处是用于表示未初始化的数据,比较少见,这里不再详谈。
参考:
http://kaito-kidd.com/2018/08/08/computer-system-float-point/
南京大学 计算机系统基础(一)主讲:袁春风老师
深入浅出IEEE浮点数表示法的更多相关文章
- IEEE浮点数表示法之出小数
纯小数的表示方法------------------------------------------------- 下面再来讲如何将纯小数转化为十六进制.对于纯小数,比如0.0456,我们需要把 ...
- IEEE Floating Point Standard (IEEE754浮点数表示法标准)
浮点数与定点数表示法是我们在计算机中常用的表示方法 所以必须要弄懂原理,特别是在FPGA里面,由于FPGA不能像在MCU一样直接用乘除法. 定点数 首先说一下简单的定点数,定点数是克服整数表示法不能表 ...
- IEEE浮点数标准
IEEE浮点数标准 阅读笔记:Computer System : A Programmmer's Perspective 基本概念 IEEE浮点数标准采用 \[V=(-1)^s\times M\tim ...
- IEEE754浮点数表示法
IEEE二进制浮点数算术标准(ANSI/IEEE Std 754-1985)是一套规定如何用二进制表示浮点数的标准.就像"补码规则"建立了二进制位和正负数的一一对应关系一样,IEE ...
- IEEE浮点数float、double的存储结构
众所周知,C的float.VB的Single都是32位浮点数变量类型(也叫单精度浮点数),C的double和VB的Double则都是64位的浮点数变量类型(也叫双精度浮点数).有些编译器还支持更屌的l ...
- 浮点数在计算机中的表示(IEEE浮点数标准)
转载自:https://wdxtub.com/2016/04/16/thin-csapp-1/
- IEEE浮点数向偶数舍
CSAPP 向偶数舍入初看上去好像是个相当随意的目标--有什么理由偏向取偶数呢?为什么不始终把位于两个可表示的值中间的值都向上舍入呢?使用这种方法的一个问题就是很容易假想到这样的情景:这种方法舍入 ...
- C语言中float,double类型,在内存中的结构(存储方式)
C语言中float,double类型,在内存中的结构(存储方式)从存储结构和算法上来讲,double和float是一样的,不一样的地方仅仅是float是32位的,double是64位的,所以doubl ...
- PostgreSQL的基础数据类型分析记录-转
src:http://www.codeweblog.com/postgresql%E7%9A%84%E5%9F%BA%E7%A1%80%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E ...
- IEEE二进制浮点数算术标准(IEEE 754)
整理自IEEE 754 IEEE二进制浮点数算术标准(IEEE 754)是20世纪80年代以来最广泛使用的浮点数运算标准,为许多CPU与浮点运算器所采用.这个标准定义了表示浮点数的格式(包括负零-0) ...
随机推荐
- chrony时间同步软件介绍
本文分享自天翼云开发者社区<chrony时间同步软件介绍>,作者:刘****苏 chrony是网络时间协议NTP的通用实现,它可以将系统时钟和`NTP服务器同步.它支持在各种条件下包括间歇 ...
- python爬虫(BeautifulSoup)爬取B站视频字幕
比如"https://www.bilibili.com/video/BV1zU4y1p7L3"这个视频,有1.2万条弹幕 首先,B站视频的弹幕是有专门的接口传递数据的:http:/ ...
- eolinker同一个自动化用例内执行不同端接口遇到的问题(主要是两套host环境共存的问题)解决方法
特别注意:需要使用全局变量或者预处理前务必阅读本链接https://www.cnblogs.com/becks/p/13713278.html eolinker内同一套环境只能配置一个host地址,如 ...
- Java编程--观察者(Observer)设计模式
观察者设计模式 观察者设计模式是一种行为设计模式,允许对象在其状态改变时通知其他依赖对象.它创建了一种发布者(Subject)和订阅者(Observer)之间的依赖关系.这种模式经常用于实现事件处理系 ...
- SpringMVC返回值
字符串 /** * 测试返回字符串 * @param model model * @return 返回的字符串,通过视图解析器调整到jsp页面 */ @RequestMapping("/te ...
- 基于Kubernetes可扩展的Selenium 并行自动化测试部署及搭建(3)——基于k8s的selenium grid集群搭建
本篇主要讲解如何使用k8s搭建selenium grid集群 Selenium Grid集群部署 1. 首先我们将通过 Kubernetes 服务进行通信以到达hub和nodes.Kubernete ...
- 流的使用之“如何将List<String>转为Map”
流的使用之"如何将List<String>转为Map" ProductIllegalCustom query = new ProductIllegalCustom(); ...
- INotifyCollectionChanged 用法简介
INotifyCollectionChanged 接口是 System.Collections.Specialized 命名空间中的一个接口,用于在集合发生更改时通知订阅者.这个接口通常在实现了集合的 ...
- Web前端入门第 55 问:JavaScript 严格模式与非严格模式区别
JavaScript 默认是非严格模式的,可以通过 "use strict"; 启用严格模式.此声明语句可以放在 JS 文件顶部,也可以放在函数内部. 启用严格模式 1.外部脚本在 ...
- 【公众号搬运】React-Native开发鸿蒙NEXT(3)
.markdown-body { line-height: 1.75; font-weight: 400; font-size: 16px; overflow-x: hidden; color: rg ...
