深入浅出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) ...
随机推荐
- 学习EXTJS6(10)面向对象的基础框架-2【统一的组件模型】很重要
用到ExtJS,UNIGUI是以ExtJS为基础的框架.因此掌握基础组件模型太重要了.确实就是让自己知道其所以然. Ext中所有可视组件都继承自Ext.Component. 1.Ext.Compone ...
- Redis-过期删除策略和内存淘汰策略
简介.我们先来看如下几个问题: ①.如何设置Redis键的过期时间 ? ②.设置完一个键的过期时间后,到了这个时间,这个键还能获取到么?假如获取不到那这个键还占据着内存吗 ? ③.如何设置Redis的 ...
- springboot整合log4j
一.默认名log4j2-spring.xml,就省下了在application.yml中配置 <console name="Console" target="SYS ...
- 【代码】Android|判断asserts下的文件存在与否,以及普通文件存在与否
作者版本:Android 11及以上 主要是发现网上没有完整的.能跑的代码,不知道怎么回事,GPT给我重写的.我只能保证这个代码尊嘟能跑,不像其他的缺胳膊少腿的. asserts 贴一下结果: boo ...
- openstack-Train部署文档
部署参考资料:1,环境准备https://blog.csdn.net/m0_61777116/article/details/123702147阿里yum源https://blog.csdn.net/ ...
- HMM - (补充) 参数求解之 F/B 算法细节
回顾 上篇通过EM算法思想来求解 HMM 的参数 \(\theta=(\pi, A,B)\) 即 初始状态概率(向量), 状态转移概率(矩阵), 发射概率矩阵. 在上帝视角, 即已知隐变量 Z , 则 ...
- ES查不到最近的数据解决方法
其实是因为索引的刷新策略导致的,不是实时刷新的. 下载开源的 ES 界面客户端ES King:https://github.com/Bronya0/ES-King 连接后,选择索引,选择flush索引 ...
- 推荐一个Elasticsearch ES可视化客户端工具:ES-King,支持win、mac、linux
ES-King:开源免费,一个现代.实用的ES GUI客户端,支持多平台. 下载地址:https://github.com/Bronya0/ES-King 我之前开源的kafka客户端kafka-ki ...
- Seata源码—9.Seata XA模式的事务处理
大纲 1.Seata XA分布式事务案例及AT与XA的区别 2.Seata XA分布式事务案例的各模块运行流程 3.Seata使用Spring Boot自动装配简化复杂配置 4.全局事务注解扫描组件的 ...
- Grind75详解
Day1 001 ToSum //O(n2) public int[] TwoSum(int[] nums, int target) { for (int i = 0; i < nums.Len ...
