浮点数的计算机表示(IEEE 754),由 UCB 数学教授 William Kahan 主要起草。后者也因其卓越贡献于1989年获得图灵奖。计算机组成原理与汇编语言这两门课均对该内容有所讲解。与课程中直接抛出公式与概念不同,我想首先与各位探讨"科学计数法"这个概念,进而讨论设计二进制的科学计数法需要涉及到哪些元素。接着,我们讨论如何在内存上表达这个方案。最后讨论计算机的具体实现。

科学计数法

我们都了解科学计数法。科学计数法的精妙之处在于,其将"量级"与"数值"两个信息拆分,让使用者对这两个信息更加明确。
12345=1.2345×10412345 = 1.2345 \times 10^412345=1.2345×104

如上,我们可以将任何有理数拆分成A=B×10CA=B \times 10^CA=B×10C的形式。值得注意的是:

  • BBB的取值范围是B∈[1,10)B\in [1,10)B∈[1,10)
  • CCC一定是一个整数

对于任何有理数,我们都可以用两个范围狭小(规则明确)的数字 B 与 C 来表示。

此外,我们知道,十进制只不过是记录数字大小的一种方式而已。历史上出现过的二进制、三进制、二十进制,都可以毫无障碍地表示数字,并且还有其独具的数学特性。

那么,二进制可以用科学计数法表示吗?答案当然是肯定的。

二进制的科学计数法

A2=B2×102CA_2 = B_2 \times 10_2^CA2​=B2​×102C​

注意,这里下标2,代表这个数是二进制。 同理,10210_2102​对应十进制中的数字2=21×1+20×02=2^1 \times 1 + 2^0 \times 02=21×1+20×0。

通过观察十进制的科学计数法形式,对于二进制,我们自然可以做出如下约定:

  • BBB的取值范围是B∈[1,2)B \in [1,2)B∈[1,2)
  • CCC一定是一个整数

这里我们补充说明一下,二进制的小数是什么样的。对于 5.255.255.25 这个十进制数,如果要将其转换为二进制:

  • 将其整数部分与小树部分分开;
  • 对于整数部分 5 ,我们使用"不断除以2取余数"的方法,得到 101 ;
  • 对于小数部分 .25 ,我们使用"不断乘以2取整数"的方法,得到 .01

关于进制转换的具体方法与背后的数学原理,我写过一篇文章进行讨论,见这里:十进制转二进制 / 八进制 / 十六进制的手算方法,及其数学原理的通俗解释。

这里,我们只需要明确,二进制是存在小数形式的,且可以表示一切十进制可表示的数(的近似)。

计算机如何记录二进制的科学计数法

接着,我们步入正题:只会表示0/1的计算机,如何记录并表达浮点数呢?

给一个32位的空间,如果不做任何约束,我们只能将其理解为一个整数,并且其取值范围为 [0,232−1][0, 2^{32}-1][0,232−1] 。

这是因为,计算机只能记录 0 和 1 这两个信息,并不能直接记录小数点点在哪里。因此,我们需要设置一定规则,取出一定位,用于表示小数点点在哪里。这必将牺牲一定的精度与取值范围。

因此,我们将这 32 位空间分为三部分:

  • 第一部分,用于表示精度,即这个数字值是多少,对应上面的B;
  • 第二部分,用于表示小数点,即量级,对应上面的C;
  • 第三部分,用于表示正负,只需要使用1位。

在 IEEE 754 中,我们分别将上述一、二、三部分叫做尾数M阶码E符号s

于是我们有了二进制的表达式:
V=(−1)s×M×2EV=(-1)^s \times M \times 2^EV=(−1)s×M×2E

为了表示尽可能多的、常用的小数,我们有如下需求

  • 对于符号位 s ,如果该位上是 0 ,则为正数;为 1 ,则为负数。
  • 对于尾数 M ,其取值范围为 [1,2)[1, 2)[1,2) ;
  • 对于阶码 E ,其为一个整数,并且取值范围应该包含负数、0、正数。

可以注意到,对于 M 、 E ,我们并不能直接用二进制表示,还需要设定一定规则。

尾数 M

假设尾数 M 一共有 f 位,则 f 可表示的整数取值范围为 [0,2f−1][0, 2^f - 1][0,2f−1] ,我们称 f 直接对应的非负整数为 C 。为了将其投影到 [0,1)[0, 1)[0,1) ,我们做出如下变换:
M=1+C2fM=1+\frac{C}{2^f}M=1+2fC​

解码 E

假设解码 E 一共有 e 位,则 e 可表示的整数取值范围为 [0,2e−1][0, 2^e - 1][0,2e−1] ,我们称 e 直接对应的非负整数为 Exp 。我们希望 E 可以取到负数,因此做出如下变换:
E=Exp−(2e−1−1)E = Exp - (2^{e-1}-1)E=Exp−(2e−1−1)

这样,我们的 E 取值范围就来到了 [−(2e−1−1),2e−1][-(2^{e-1}-1), 2^{e-1}][−(2e−1−1),2e−1] 。

总结

有了如上设计的规则,我们便知晓了计算机记录浮点数的方式,以及转换流程。以下图为例。

知识点与例题

上面我们讨论了 IEEE 754 的思想,但是并不严谨,比如:

  • 正负无穷该怎么表达?
  • 如此表示会不会造成空间的浪费?

因此,我们从数学上严谨地讨论一道例题,考虑一下规格化浮点数。例题源自我的汇编语言笔记。

题目

给定一个浮点格式(IEEE 754),有k位指数和n位小数,对于下列数,写出阶码E、尾数M、小数f和值V的公式。另外,请描述其位表示。

  • 数5.0;
  • 能够被准确描述的最大奇数;
  • 最小的正规格化数。

解决

前置知识一:IEEE 754

IEEE 754约定,计算机中浮点数二进制表示为:

数字形式:(−1)sM2E(-1)^s M 2^E(−1)sM2E

  • 符号:s
  • 尾数:M,是一个位于区间[1.0, 2.0)内的小数
  • 阶码:E

编码形式:

s exp frac

exp域:E(注意,E要进行变换,再存储在exp中);
frac域:M。

前置知识二:规格化浮点数(Normalized)

这里讨论到规格化浮点数(Normalized):

  • 满足条件:exp不全为0且不全为1。
  • 真实的阶码值需要减去一个偏置(biased)量:
    • E = Exp - Bias
    • Exp:exp域所表示的无符号数值
    • Bias的取值:
    • 单精度数:127(Exp:1…254,E:-126…127)
    • 双精度数:1023(Exp:1…2046,E:-1022…1023)
    • Bias = 2^{e-1} - 1,e = exp的域的位数
  • frac的第一位隐含1:M = 1.xxx…x_2
    • 因此第一位的“1”可以省去,xxx…x:bits of frac
    • Minimum when 000…0 (M = 1.0)
    • Maximum when 111…1 (M = 2.0 - \epsilon)
前置工作一:整理变量关系

Bias=2e−1−1Bias = 2^{e-1} - 1Bias=2e−1−1

E=exp−BiasE = exp - BiasE=exp−Bias

V=(−1)sM2EV = (-1)^s M 2^EV=(−1)sM2E

则E为dec(exp)−(2e−1)dec(exp) - (2^{e} - 1)dec(exp)−(2e−1)

E最大值为2e−1−1−(2e−1−1)=2e−1−12^e - 1 - 1 - (2^{e-1} - 1)= 2^{e-1} - 12e−1−1−(2e−1−1)=2e−1−1。(为什么不是2e−1−(2e−1−1)2^e - 1 - (2^{e-1} - 1)2e−1−(2e−1−1)呢?因为有规定:exp全部取1为“非规格化浮点数”,因此规格化浮点数中exp不能全部取1,顶多为(1)*(0)

E的最小值为1−(2e−1−1)=2−2e−11-(2^{e-1}-1)=2-2^{e-1}1−(2e−1−1)=2−2e−1。(为什么不是0−(2e−1−1)0-(2^{e-1}-1)0−(2e−1−1)呢?因为有规定:exp全部取0为“非规格化浮点数”,因此规格化浮点数中exp不能全部取0,顶多为(0)*(1)

前置工作二:总结特性

抛开例题,来看一个例子:

  • 8位浮点数表示:exp域宽度为4 bits,frac域宽度为3 bits。则,其偏置量的值为2^(4-1) - 1 = 7.
  • 其他规则符合IEEE 754规范。

取值范围如下表。

s exp frac E value
0 0000 000 -6 0
0 0000 001 -6 1/8 * 1/64 = 1/512
0 0000 010 -6 2/8 * 1/64 = 2/512
0 0000 110 -6 6/8 * 1/64 = 6/512
0 0000 111 -6 7/8 * 1/64 = 7/512
0 0001 000 -6 8/8 * 1/64 = 8/512
0 0001 001 -6 9/8 * 1/64 = 9/512
0 0110 110 -1 14/8 * 1/2 = 14/16
0 0110 111 -1 15/8 * 1/2 = 15/16
0 0111 000 0 8/8 * 1 = 1
0 0111 001 0 9/8 * 1 = 9/8
0 0111 010 0 10/8 * 1 = 10/8
0 1110 110 7 14/8 * 128 = 224
0 1110 111 7 15/8 * 128 = 240
0 1111 000 n/a inf

可以看出,假设frac有f位,则M可视为:

M={0+12f×C,if all(exp==0)1+12f×C,if both ’0’ and ’1’ in expn/a,if all(frac==1)M=\left\{ \begin{aligned} 0+\frac{1}{2^f} \times C &, \; & \text{if all(exp==0)} \\ 1+\frac{1}{2^f} \times C &, \; & \text{if both '0' and '1' in exp} \\ \text{n/a} &, \; & \text{if all(frac==1)} \\ \end{aligned} \right.M=⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧​0+2f1​×C1+2f1​×Cn/a​,,,​if all(exp==0)if both ’0’ and ’1’ in expif all(frac==1)​

其中,C是整数,由frac决定,即C=dec(frac)C=dec(\text{frac})C=dec(frac);

并且C满足0≤C≤2f−10 \le C \le 2^f - 10≤C≤2f−1。

则浮点数V的十进制即为:

V={(−1)s×22−2e−1×(0+12f×C),if all(exp==0)(−1)s×2[dec(exp)−(2e−1)]×(1+12f×C),if both ’0’ and ’1’ in exp(−1)sinf or n/a,if all(frac==1)V=\left\{ \begin{aligned} (-1)^s\times2^{2-2^{e-1}}\times(0+\frac{1}{2^f} \times C) &, \; & \text{if all(exp==0)} \\ (-1)^s\times2^{[dec(exp) - (2^{e} - 1)]}\times(1+\frac{1}{2^f} \times C) &, \; & \text{if both '0' and '1' in exp} \\ (-1)^s \; \text{inf or n/a} &, \; & \text{if all(frac==1)} \\ \end{aligned} \right.V=⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧​(−1)s×22−2e−1×(0+2f1​×C)(−1)s×2[dec(exp)−(2e−1)]×(1+2f1​×C)(−1)sinf or n/a​,,,​if all(exp==0)if both ’0’ and ’1’ in expif all(frac==1)​

dec(exp)−(2e−1)dec(exp) - (2^{e} - 1)dec(exp)−(2e−1)也可写作EEE:

V={(−1)s×22−2e−1×(0+12f×C),if all(exp==0)(−1)s×2E×(1+12f×C),if both ’0’ and ’1’ in exp(−1)sinf or n/a,if all(frac==1)V=\left\{ \begin{aligned} (-1)^s\times2^{2-2^{e-1}}\times(0+\frac{1}{2^f} \times C) &, \; & \text{if all(exp==0)} \\ (-1)^s\times2^{E}\times(1+\frac{1}{2^f} \times C) &, \; & \text{if both '0' and '1' in exp} \\ (-1)^s \; \text{inf or n/a} &, \; & \text{if all(frac==1)} \\ \end{aligned} \right.V=⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧​(−1)s×22−2e−1×(0+2f1​×C)(−1)s×2E×(1+2f1​×C)(−1)sinf or n/a​,,,​if all(exp==0)if both ’0’ and ’1’ in expif all(frac==1)​

其中,eee、fff分别为exp、frac位数,为常数。

解决问题一:数0.5

较为简单,直接解决如下。

0.5          // 转换为二进制 ==>
0.1         // 移动小数点,使其在最左边的1之后
M   = 1.0  // 小数点后的数字存储在frac中
E   = -1   // 因为是左移
frac= 0*   // 共n位
exp = E + Bias= -1 + (2^(e-1) - 1)

则,位的描述为:

s exp frac
0 bin(-1 + (2^(e-1) - 1)) 00…(共n位)
解决问题二:能够被准确描述的最大奇数

根据前置工作二,可以看出,对于规格化浮点数可化简为:

V=(−1)s×2E×(1+12f×C)=(−1)s×(2E+2E−f×C)\begin{aligned} V & = & (-1)^s\times2^{E}\times(1+\frac{1}{2^f} \times C) \\ & = & (-1)^s \times (2^{E}+2^{E-f} \times C) \end{aligned}V​==​(−1)s×2E×(1+2f1​×C)(−1)s×(2E+2E−f×C)​

现在的任务有两个:

  • 是整数,不能有小数(则EEE应大于等于fff);
  • 是奇数(2E2^E2E不是奇数,因此使2E−f×C2^{E-f} \times C2E−f×C为奇数,则2E−f2^{E-f}2E−f取1,则取E=fE=fE=f)。

下面分类讨论:

情况一:E可以取到f时,

即2e−1−1≥f2^{e-1} - 1 \ge f2e−1−1≥f时,

EEE取fff,CCC取其能取的最大奇数,对应的二进制为:
exp:dec2bin(f+(2e−1−1)f + (2^{e-1} - 1)f+(2e−1−1)),frac:1*(frac全为1)

情况二:E取不到f时,

这种情况不可能,因为E取不到f,则很多整数都不能表示。

解决问题三:最小的正规格化数

观察:

V=(−1)s×2E×(1+12f×C)=(−1)s×(2E+2E−f×C)\begin{aligned} V & = & (-1)^s\times2^{E}\times(1+\frac{1}{2^f} \times C) \\ & = & (-1)^s \times (2^{E}+2^{E-f} \times C) \end{aligned}V​==​(−1)s×2E×(1+2f1​×C)(−1)s×(2E+2E−f×C)​

则sss取000,EEE、CCC分别取最小。

由前置工作一,EEE取2−2e−12-2^{e-1}2−2e−1,CCC取000,对应的二进制为:
exp:0*1,frac:0*

后记:我第一学习浮点数是在2019年年末,当时对于浮点数的笔记和理解是有问题的。在此感谢一位湖南大学的朋友(公众号 / CSDN:梓酥),给我发邮件,指出我的问题~

​此外,也欢迎大家与我交流,公众号:Piper蛋窝,微信号:PiperLHJ

二进制的科学计数法?白话谈谈计算机如何存储与理解小数:IEEE 754相关推荐

  1. 导出excel 并且处理长数字,处理科学计数法,以文本形式存储的数字

    /// <summary>/// 导出Excel文件,并自定义文件名/// </summary>/// <param name="dtData"> ...

  2. 单精度浮点数计算机存储的理解(IEEE 754)

    浮点数剖析 以下是该标准对浮点数格式的描述. [编辑]本文表示比特的约定 把W个比特(bit)的数据,从内存地址低端到高端,以0到W−1编码.通常将内存地址低端的比特写在最右边,称作最低有效位(lea ...

  3. 科学计数法e/E?计算机?表示?

    计算机表达10的幂是一般是用E或e,即 1.03乘10的9次方,可简写为"1.03E+09"的形式 -1.03乘10的9次方,可简写为"-1.03E+09"的形 ...

  4. 计算机浮点数科学计数法运算,浮点数在计算机中的表示

    浮点数在计算机中的表示 最后编辑于:2010-4-13 计算机中数字是以0和1二进制保存的,我们熟悉的是整数的如何在计算机中表示,那么浮点数是如何表示的呢? 一.    转换 我们先来看看如何将十进制 ...

  5. 浮点数——科学计数法、浮点数表示、加减运算和浮点数的使用

    目录 1.2浮点数 1.2.1 科学计数法 1.2.2 浮点数表示 1 符号位 2价码位 1.2.3 加减运算 1.2.4 浮点数的使用 1.2浮点数 浮点数是采用科学计数法来表示的,由符号位.有效数 ...

  6. Js 对小数的处理(科学计数法 , 显示精度)

    对数字进行格式化输出,是非常有意义的一件事情,例如许多时候,我们希望一个数字能够输出为指定格式的字符串,拿25.9878来说,我们可能会希望它能保留两位小数来说出,即结果为25.99,或者对于0.34 ...

  7. 怎么转换科学计数法字符串_【编码技巧】python字符串格式化教你正确打印

    点击上方蓝字关注我吧! %运算符用来格式化字符串.在字符串内部,%s表示用字符串替换,%d表示用整数替换,有几个%?占位符,后面就跟几个变量或者值,顺序要一一对应.如果只有一个%?,括号可以省略.用% ...

  8. 【C/C++】小数的输出 %e的用法 用科学计数法输出数据 %e输出00

    小数的输出 %e的用法 %e是printf的格式控制字符,用于指定浮点类型数据使用指数形式输出 浮点类型分为整数部分和小数部分,它们由点号.分隔,例如 0.0.75.0.4.023.0.27.-937 ...

  9. 计算机中的科学计数法

    计算机中的科学计数法(带有E的表示方法) 以 E+n 替换部分数字,其中 E(代表指数)表示将前面的数字乘以 10 的 n 次幂.例如,用 2 位小数的"科学记数"格式表示 123 ...

最新文章

  1. python安装mysql数据库教程,Python配置mysql的教程(必看)
  2. CodeForces - 222C Reducing Fractions(唯一分解定理)
  3. python命令行模式和交互模式区别_对命令行模式与python交互模式介绍
  4. Android Gradle进阶配置指南
  5. 实现审批系统_我市工程建设项目审批系统实现与 省监管平台数据互联互通
  6. 如何使用ps制作一寸照
  7. 爱心的数学函数方程_数学里有哪些可以示爱的图像?它们的函数方程又是什么?...
  8. 服务器u盘pe制作,u盘winpe启动盘制作
  9. 数位板使用技巧、个人数位板见解、插画教程...
  10. 企业微信发送信息异常的临时处理方案
  11. Java中String使用及分析(UTF-8简单编码/解码器实现)
  12. Android系统启动之BOOT_COMPLETED广播
  13. 锐捷(七)设备软件版本升级更新
  14. 高分一号PMS数据预处理
  15. 开发谷歌浏览器插件会上瘾,搞了一个JSONViewer,一个页面格式化多条JSON,提升工作效率...
  16. 关于django外键设置的问题
  17. 快捷复制网页文字小技巧
  18. iPhone卫星功能仅用于紧急通信;韩国通过立法禁止苹果、谷歌垄断支付系统;Linux 5.14 版本发布|极客头条
  19. C++:Error C 1010:在查找预编译头时遇到意外的文件结尾。
  20. 元宇宙,只是一时兴起的想法?

热门文章

  1. 测试~在使用共通处理时,需要注意的问题 ~ 使用前,清空Form中的值。
  2. 【Oracle】使用logmnr工具挖掘日志
  3. 1.5.7、CDH 搭建Hadoop在安装之前(定制安装解决方案---配置单用户模式)
  4. [课后作业] 第032讲:异常处理:你不可能总是对的
  5. 【JAVA错误笔记】 - 【Could not open ServletContext resource [/WEB-INF/applicationContext.xml]解决方法】
  6. js做四则运算时,精度丢失问题及解决方法
  7. com.alibaba.dubbo.rpc.RpcException: Failed to invoke remote method解决方法
  8. 在Bash中重定向stderr和stdout
  9. micropython教程nucleo-f767zi开发板_Micropython教程之TPYBoard开发板制作电子时钟(萝卜学科编程教育)...
  10. 力扣——合并两个有序链表