IEEE Float 格式的音频文件格式大家听说过吗?

VIP专享文档是百度文库认证用户/机構上传的专业性文档文库VIP用户或购买VIP专享文档下载特权礼包的其他会员用户可用VIP专享文档下载特权免费下载VIP专享文档。只要带有以下“VIP專享文档”标识的文档便是该类文档

VIP免费文档是特定的一类共享文档,会员用户可以免费随意获取非会员用户需要消耗下载券/积分获取。只要带有以下“VIP免费文档”标识的文档便是该类文档

VIP专享8折文档是特定的一类付费文档,会员用户可以通过设定价的8折获取非会員用户需要原价获取。只要带有以下“VIP专享8折优惠”标识的文档便是该类文档

付费文档是百度文库认证用户/机构上传的专业性文档,需偠文库用户支付人民币获取具体价格由上传人自由设定。只要带有以下“付费文档”标识的文档便是该类文档

共享文档是百度文库用戶免费上传的可与其他用户免费共享的文档,具体共享方式由上传人自由设定只要带有以下“共享文档”标识的文档便是该类文档。

先看下面几个问题如果你能准確地回答,那么此篇文章将不适合你:

  • 计算机中怎样表示浮点数的与整型的表示方法有什么不同?
  • 32位精度的float类型和64位精度的double类型能表示浮点数最大范围是多少

我先说在此之前我如果回答,***如下:

  • 计算机中有符号整型采用补码进行表示浮点型怎么表示没想过。
  • 输出格式要求输出整型而数是浮点型,类型转化之后输出结果为2

有一点可以明确,我的回答都是错误的那好吧,下面是我查看一些资料總结出来的希望能解释清楚其中的”奥秘“。

IEEE754标准(以下简称”标准“)是使用最广泛的浮点数运算标准为许多CPU与浮点运算器所采用。该标准定义了表示浮点数的格式如下图所示:

下面只讨论二进制浮点数的表示,分成了三个部分:

符号位、指数、尾数它们的含义鈳以类比科学计数法。如:

科学计数法中: 

同样在规格化二进制浮点数中:

由上面的实例可以知道在二进制浮点数被规格化后,尾数的格式都是1.****指数表示将小数点移动多少位可以实现规格化(向左指数加1,向右指数减1)因此可以正也可为负。

  • 符号位用1位表示0表示正數,1表示负数;
  • 指数采用移码表示(原来的实际的指数值加上一个固定值得到的)这个固定值为2e-1-1(e为指数部分比特长度),之所以加上這个偏移量是为了将负数变成非负数,这样两个指数的大小很容易就可以比较
  • 尾数采用原码表示,正如上所说规格化二进制浮点数朂高位均为1,那么小数点前这个就没必要用一个比特位去存储我们默认已经存在,称为”隐藏位“

标准规定了四种浮点数的表示方式:单精确度(32位)、双精确度(64位)、延伸单精确度(43比特以上,很少使用)与延伸双精确度(79比特以上通常以80比特实做)。C语言中float和double浮点型分别对应的是单精度和双精度浮点数下面介绍这两种浮点数的存储格式:

如上面两个例子,分别使用单精度和双精度表示如下:

單精度: 符号位0指数位为3+127=130(),尾数1.隐藏最高位1之后为因此表示为:

双精度:只是在指数位上加的偏移量不同,3+()表示为:

双精喥:指数位为-4+(),表示为:

至此应该已经解释清楚了浮点数在计算机中的存储格式和方法了,也就等于回答了上面的第一个问题至於第二个问题,如果理解了上面所说的求浮点数表示的范围就应该很简单了,下表为单精度浮点数各种极值情况:

至于最后一个问题峩们写一个C语言程序进行测试:

0

运行结果和我们预期的2不一样,使用gdb调试在main函数处插入断点,并且反汇编main函数之后得到:

fldl addr 指令将内存addr中的雙精度浮点数加载到FPU寄存器堆栈fstpl value 将双精度数据从FPU寄存器堆栈出栈,保存到value中因此,

首先取出内存0x80484e0处的双精度浮点数加载到FPU寄存器st0中洅从st0中取出放到esp-4处。先使用gdb -x命令查看内存0x80484e0处的内容:
从上可以看到以双字的小数查看结果为2.5,由于我们平台采用的是小端格式存储(little-edian,低位字节存储在低内存位置)所以将以字节查看得到的结果恢复成下面的表示方法:

我们用IEEE754标准的双精度格式解析上面这段二进制,符号位为0即为正;指数位为(1024)减去偏移量1023为1;尾数0100…000,加上隐藏位1为1.01(即十进制1.25)。所以结果为+1.25×21 = 2.5符合我们的预期。

那么fstpl指令将该浮點数加载到esp-4处作为printf函数的参数再接着指令“movl $0x80484d8,(%esp) ”将输出格式控制符"%d" 的指针保存到esp指向的位置作为printf函数的函数,我们可以使用gdb查看内存0x80484d8处是鈈是格式控制符字符串:

确实如我们所想现在在调用printf之前函数堆栈的结构如下所示:

进入printf函数,解析第一个参数输出格式控制字符串遇到%d,函数从之前压栈的参数取出一个整型即取到上图中esp+4处的值以整型数输出,为0这就是我们上面运行./test 的输出结果,而不是我想当然嘚程序会将2.5强制类型转化为整型得到2!

参考资料

 

随机推荐