关于浮点数的存储和编码方式

来源:互联网 发布:男士围巾品牌 知乎 编辑:程序博客网 时间:2024/04/30 12:28

前奏--关于存储&表示形式

  •   正整数在内存中以其源码形式存储,且其3码(源码反码补码)相同,负整数在内存中以其补码形式存储(其绝对值原码取反加一)。
  •   小尾存储 -- 以字节为单位,按照数据类型长度,低数据位存放在内存的低端,高数据位存放在内存的高端。
  •   大尾存储 -- 与小尾相反,低数据位存放在内存的高端,低数据位存放在内存的低端。
疑问1?如何判断一段数据是有符号还是无符号类型呢?
  •   要看指令或已知的函数是如何操作这块内存地址,根据操作方式或函数相关定义得出该地址的数据类型(如MessageBox的参数4为无符号整数)。

浮点数

我们调一段代码


查看变量fnNum在内存中的值


疑问2?12.25在内存中的表示值怎么是 0x41440000 ? 下面我们解决这个疑问。


浮点数的存储

  •   浮点数不是直接转为二进制数存储,而是将浮点数转成二进制重新编码再存储,C/C++的浮点数是有符号的。
  •   浮点数的操作不会用到通用寄存器,而会使用浮点协处理器的浮点寄存器,专门处理浮点数。
  •   浮点数强制转换为整数时,不会四舍五入,而会向0去整。注意 printf 函数会自动四舍五入。

浮点数的编码方式

浮点数编码转换采用的是IEEE规定的编码标准,float 和 double 的转换原理相同。
IEEE规定:首先将浮点数转为二进制,并以科学记数法表示,并将浮点数(4字节32位)拆分为3部分:
  •   符号域:1位,  占浮点数的最高位(31位),0正1负。
  •   指数域:8位,  占第23到30位,表示科学记数法中的指数部分,存放小数点的位置信息。初始值127,每+1表示左移了1位,-1反之。(不足高位补0)
  •   尾数域:23位,占第0到22位,表示科学记数法中的尾数部分,存储没有小数点时的数据和符号(整数部分1舍去)。(不足低位补0)

根据上面我们对12.25进行IEEE编码

12.25二进制表示:1100.01,用科学记数法表示为1.10001,小数点向左移3位,则指数域为3+127,尾数域为10001000000000000000000(不足23位时,低位填0补充),符号域为0,则最终表示为 01000001010001000000000000000000,转为16进制为 0x41440000。


疑问3 ?浮点数值的比较?

浮点数在转换过程中都会有误差的,所以浮点数不能直接比较其大小,一般在比较两个浮点数的时候是比较他们之间的差值,如果两个数之间的差值处于一个能接受的范围之内的话,那么,我们就认为这两个浮点数是相等的。这也解释了在比较浮点数是否为0时,要做一个区间的比较而不是直接进行等值比较。

一般来说这个可以接受的误差值就是计算机的转换误差,C++标准库提供了这个误差,你可以从numeric_limits模板库的epsilon函数取得numeric_limits<float>::epsilon() 

if( abs(a-b) <= numeric_limits<float>::epsilon() )    ShowMessage("两个数一样大");else       ShowMessage("两个数不是一样大"); 
double 同(numeric_limits< double >::epsilon() )。

double型的IEEE编码

double 占8个字节,符号位1位,指数位11位(初始为1023),其余为尾数位。其转换流程与 float 同。


浮点数指令就不说了,此文重在浮点数的编码方式。(总结自钱老师《C++反汇编与逆向分析技术揭秘》)

0 0