深入浅出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) ...
随机推荐
- 面试题:Linux 系统基础 (二)
Linux系统中的定时任务有哪些类型,它们是如何配置的? Linux系统中的定时任务主要有两种类型:Cron作业和at作业. 1.Cron作业: 使用crontab命令配置和管理. 配置周期性执行的任 ...
- Zephyr重定向日志打印到USB串口
nRF52840DK开发板的例程大多数是从硬件串口打印日志,然后硬件串口在开发板上通过Jlink转换为USB串口,最后打印到电脑上. 这里给出通过52840自己的USB串口打印日志的方法. 以zeph ...
- docker发布简单python服务
进入机器创建一个目录mkdir dockerbuild1.编写简单flask代码vi flaskapp.pyfrom flask import Flaskimport os app = Flask(_ ...
- Greenplum优化总结
Greenplum优化总结 GP优化需要了解清理缓存.性能监控.执行计划分析等知识.优化主要包含以下四方面: 表.字段,SQL,GP配置.服务器配置,硬件及节点资源. 一. 清理缓存: #!/usr/ ...
- 2025年BI工具趋势:DataFocus与FineBI的技术创新对比
1. 摘要 DataFocus 和 FineBI 都是旨在帮助企业利用数据进行决策的商业智能 (BI) 产品.DataFocus 强调其下一代.基于搜索的 BI 方法,侧重于易用性和快速仪表板创建,尤 ...
- App自动化环境部署
1.所需工具 Android-SDK:自行百度下载 Appium-Desktop:自行百度下载 真机或模拟器:自行准备 2.部署步骤 1)配置Android-SDK 解压Android-SDK压缩包 ...
- 使用 StreamJsonRpc 在 ASP.NET Core 中启用 JSON-RPC
StreamJsonRpc 是微软开发的一个开源库,用于在 .NET 平台中实现基于 JSON-RPC 2.0 规范 的远程过程调用(RPC).它通过流(如管道.网络流等)实现高效的跨进程或跨网络通信 ...
- 备份一个迭代查找TreeViewItem的辅助函数
private TreeViewItem FindTreeItem(TreeViewItem item, Func<TreeViewItem, bool> compare) { if (i ...
- 通用型产品发布解决方案(SpringBoot+SpringCloud+Spring CloudAlibaba+Vue+ElementUI+MyBatis-Plus+MySQL+Git+Maven)03
通用型产品发布解决方案(基于分布式微服务技术栈:SpringBoot+SpringCloud+Spring CloudAlibaba+Vue+ElementUI+MyBatis-Plus+MySQL+ ...
- System.nanoTime() 方法
System.nanoTime() 方法 JDK1.5之后java中的计时给出了更精确的方法:System.nanoTime(),输出的精度是纳秒级别,这个给一些性能测试提供了更准确的参考. 注:1 ...