← 深入理解计算机系统 CSAPP 读书笔记

4[VB]浮点数据类型


视频地址:
课件地址:
对应于书本的2.4。
如有错误请指出,谢谢。

1 浮点数简介

浮点表示对形如 的有理数进行编码,比较适用于非常大的数字、非常接近0的数字。它常常不会太多关注运算的准确性,而是把实现的速度和简便性看得比数字精确性更重要。1985年提出了IEEE标准754,仔细制定了表示浮点数机器运算的标准,后续所有计算机都支持这个标准,极大提高了程序可移植性。
首先会介绍IEEE浮点表示方法,然后由于数字不能精确被表示,所以会介绍浮点数的舍入问题。最后介绍浮点数相关的运算。

2 IEEE浮点表示

IEEE浮点表示使用 表示数字。其中包含三部分:
  • 符号(Sign)s:用来确定V的正负性,当s=0时表示正数,s=1时表示负数。用一个单独的符号位直接进行编码。
  • 尾数(Significand)M: 是一个二进制小数,通常介于1和2之间的小数。使用k位二进制进行编码的小数。
  • 阶码(Exponent)E:对浮点数进行加权。使用n位进行编码的正数
C语言中有单精度精浮点数float,其中s=1、k=8、n=23;还有双精度浮点数double,其中s=1、k=11、n=52。
我们可以根据尾数和阶码的不同取值,将其分成三种情况:
  1. 规格化的值: 时, ,其中 ,由此能将E重新投影到正负值,并且能够和非规格化进行平滑; ,因为我们可以通过调整E使得 ,所以通过这种形式将尾数变成 的形式,就能获得额外的精度。规格化数能够表示大范围的数。
  1. 非规格化的值: 时, ,由此来保证和规格化值的连续性;非规格化数能够表示正负0以及趋近于0的数。
  1. 特殊值:当阶码全为1时,如果尾数全为0,则表示无穷,比如两个很大的数相乘,或除以0时;否则表示NaN(Not a Number),比如求-1的根号。
通过上面我们可以观察到几个现象
  1. 非规格数稠密地分布在靠近0的区域;
  1. 有些数的间隔是等距的,因为当exp值不变,在frac尾数区域进行增加会乘上相同的指数;
  1. 越大的数间隔越大,因为比较大的数,它的指数 会比较大,使得每次变化量会比较大。
根据二进制编码计算数值:
  1. 计算
  1. 计算阶码的值exp和尾数的值frac
  1. 如果为规格化值,则 ;如果为非规格化值,则
  1. 计算最终的值
 
我们以正数为例(s=0),说明几个比较特殊的值:
 
  • 0:只有非规格化才能表示0,exp和frac全部为0时,结果为0。
  • 最小的正非规格化数: 是固定值,在frac取值范围内的最小值正数是 ,则 ,所以
  • 最大非规格化数:E还是固定值 ,在frac取值范围内的最大值是 ,则 ,所以
  • 最小规格化数:exp的最小值为 ,所以 ;frac全0时,M取得最小值1,所以
  • 1:要表示1,则需要用规格化来表示,当frac全为0时,M=1,需要让E=0,则 ,即exp为
  • 最大规格化数:exp的最大值为 ,frac的最大值为全1,即 ,所以 ,所以
 
 
IEEE设计的好处:
  1. 最大非规格化值 和最小规格化值 之间的幅度是 ,是n位尾数所能表示的最小值,可以看成是光滑转变
  1. 从最小非规格化数到最大规格化数的位向量的变化是顺序的,和无符号整数的排序相同。所以可以用无符号数的排序函数来对浮点数进行排序注意:负无穷转化为无符号数进行比较时会有问题。
 
将十进制化为浮点数表示:
 
以12345为例,我们推算单精度浮点数的编码
  1. 计算
  1. 将12345化为二进制数
  1. 首先将二进制数其化成小于1的科学计数法 ,很明显指数14不为 ,所以是规格化数,所以将其转化为大于1的科学计数法 ,所以
  1. 因为 ,所以frac的编码为 。因为 ,所以
  1. 将frac和exp的二进制编码扩展到对应位数并拼接在一起,补上符号位就为最终结果
 
注意:要在exp前面补0,在frac后面补0。因为exp表示整数,frac表示小数。
 
对比无符号数的编码,我们可以发现:因为无符号数一定大于0,所以相同的数想用浮点数编码只能使用规范化数进行编码,而规范化数会将frac的最高有效位1去掉,所以无符号数的编码和浮点数编码,在frac部分是相似的,浮点数会少了最高有效位的1。而无符号数的其他部分就是0,而浮点数的其他部分是表示指数的编码。

3 浮点数舍入

浮点数由于有限的位数,所以对于真实值x,我们想要用一种系统的方法来找到能够用浮点数表示的“最接近的x”匹配值x',这个过程就称为舍入
常见的舍入方法有四种:向零舍入、向上舍入、向下舍入以及向偶数舍入。以十进制为例可以看以下表格
其中比较特殊的是向偶数舍入:如果处于中间值,就朝着令最后一个有效位为偶数来舍入;否则朝着最近的值舍入。比如1.40,由于靠近1就朝1舍入;1.6靠近2就朝2舍入;1.50位于十进制的中间值,就朝着偶数舍入,所以为2。
向偶数舍入的意义:如果对一系列值进行向上舍入,则舍入后的平均值会比真实值更大;使用向下舍入,则舍入后的平均值会比真实值更小。通过向偶数舍入,每个值就有50%概率变大、50%概率变小,使得总的统计量保持较为稳定。
十进制的中间值为 ,比这个中间值大就向上舍入,比这个中间值小就向下舍入,否则朝着偶数舍入。
而二进制的中间值是 ,比如 就比中间值大, 就比中间值小。而且二进制中,当最后一个有效位为0时,为偶数。比如
  • 10.00011:由于011比中间值小,所以直接向下舍入,为10.00
  • 10.00110:由于110比中间值大,所以直接向上舍入,为10.01
  • 10.11100:由于100为中间值,而10.11最后一个有效位1位奇数,所以向上舍入为偶数11.00
  • 10.10100:由于100为中间值,而10.10最后一个有效位0位偶数,所以直接向下舍入10.10

4 浮点数运算

浮点数运算无法直接通过在位向量上运算得到。

4.1 浮点数乘法

对于两个浮点数 ,计算结果为 ,其中
  • 如果 ,就将frac右移一位,并对E加一。
  • 如果E超过了表示范围,就发生了溢出。
  • 如果M超过了表示范围,对frac进行舍入。
 
数学性质:
  • 可交换
  • 不可结合:可能出现溢出和不精确的舍入,比如 ,而
  • 不可分配:如果分配了可能会出现NaN,比如 ,而
  • 保证,只要 ,则

4.2 浮点数加法

对于两个浮点数 ,计算结果为 ,其中s和M是对其后的运算结果,
  • 如果 ,则frac右移一位,并对E加1。
  • 如果 ,则frac左移一位,并对E减1。
  • 如果E超过表示范围,就发生溢出。
  • 如果M超过表示范围,就对frac进行舍入。
数学性质:
  • 由于溢出,可能得到无穷之。
  • 可交换
  • 不可结合(由于舍入),因为较大的数和较小的数相加,由于舍入问题,会将较小的数舍入,比如
  • 除了无穷和NaN,存在加法逆元。
  • 满足单调性,如果 ,则对于任意a、b和x,都有 。NaN除外。无符号数和补码由于溢出会发生值的跳变,所以不满足单调性。
注意:需要考虑好清楚数值的范围,如果计算的数值范围变化很大,需要重新结合或改变运算顺序,避免由于溢出或舍入出现计算问题。

5 C中的浮点数

C中提供了floatdouble两种精度的浮点数。由于编码不同,所以在浮点数和整型数之间强制类型转换时,会修改编码,并且会出现溢出和舍入。
  • float/double转换成int:首先小数部分会被截断,也就是向0舍入。float的尾数部分为23字节,比int的32字节小,所以int可以精确表示float的整数部分,而double的尾数有52位,可能会出现舍入。并且当超过int的取值范围或NaN时,微处理器会指定 为整数不确定值,即对应的 ,所以一个很大的浮点数转化为int时,可能会出现负数。
  • int或float转换为double:double尾数有52位,而int只有32位,float只有23位,所以double会精确表示int和float,不会出现溢出和输入。
  • int转换为float:不会发生溢出,但是由于float尾数位数比较少,会出现舍入。
  • double转换为float:可能会出现溢出和舍入。
总结:超过数值表示范围,会发生溢出;尾数较短,会发生输入。
 

 
课堂作业:
  • x==(int)(float)x:int有32位,float尾数有23位,从int强制类型转换到float会出现舍入,所以错误。
  • x==(int)(double)x:int有32位,double尾数有52位,所以从int强制类型转换到float不会出现舍入,所以正确。
  • f==(float)(double)f:double的精度和范围都比float大,所以能够无损地从float强制类型转换到double,所以正确。
  • d==(double)(float)d:因为float的精度和范围都比double小,可能会出现溢出和输入,所以错误。
  • f==-(-f):因为只要改变一个符号位,所以正确。
  • 2/3==2/3.0: 因为2/3是int类型,会舍入变成0,而2/3.0是double类型,会得到数值,所以错误。
  • d<0.0推出((d*2)<0.0):乘2相当于exp加一,如果出现溢出,也是无穷小,所以正确。
  • d>f推出f>-d: 只要改变一个符号位,所以正确。
  • d*d>=0.0: 正确。
  • (d+f)-d==f:不符合结合律,可能会出现舍入和溢出。

Nobelium is built with ♥ and ⚛ Next.js. Proudly deployed on ▲Vercel.

© Ashinch 2021 桂ICP备18011166号-1