目录
最高位是符号位,表示正负
去掉符号位往后数8位 是指数域.
最后的23位则表示尾数.
1.正数浮点转为十六进制表示
-
2.浮点数转为16进制存储
现在我们要把浮点数转为十六进制存储在内存里.转换步骤
1.将一个浮点数转化为二进制例如:12.25 转为2进制 = 1100.01
整数直接转为二进制即可. 小数不断 * 2 取整.
例如: 0.25
0.25 * 2 = 0.5 取整 = 0
0.5 * 2 = 1.0 取整就是1
所有12.25 转为二进制表示就是 1100.01
2.计算指数位
计算指数位首先移动小数点位置到符号位置除最高位为1的地方.
也就是符号位也好.不是符号位也好.移动到最高位为1的地方. 7.25 转换之后是
0111.01 移动到最高位则是 1.1101.
1100.01 移动 1.10001 总共移动了3位.每次移动一位,指数+1
因为指数为移动了三位.所以 3 + 127(8位) = 130 转为二进制 10000010 这个就是指数位.
也就是上图中所说的符号位后面数8位是指数位. 我们上边计算的就是指数位的值.
为什么 +127.因为可能会出现负数.十进制127可以表示二进制的01111111. IEEE浮点编码规定
当指数域< 0111111的时候,就是一个负数.如果大于01111111的时候就是一个正数. 所以01111111为0. IEEE浮点编码规定的.所以只要记住即可. 127即可. 也可以理解为指数域是8位,表示的数值是128.但IEE规定了.所以-1 指数最大值 - 1即可.
3.计算尾数位
经过上面计算我们符号是1,但是符号位基本不变.因为是正数浮点.所以符号位为0:
指数位为: 130 10000010
现在计算尾数位. 尾数位就是我们移动小数点之后的数值
1.10001 尾数位就是 10001,但是他不组23位.所以我们补0填充.
1000 1000 0000 0000 0000 000 补0之后,我们需要从左到右,按照4个字节分开
100 0100 0000 0000 0000 0000 分开之后.
此时加上我们之前的符号位以及指数位
0100 0001 0100 0100 0000 0000 0000 0000 这是拼接好的.我们转换为16进制进行存储
0x41440000 那么在内存中,我们的浮点数12.25 其实就是16进制 0x41 44 00 00 进行存储的.
2.负数浮点转为十六进制表示.
负数跟上边一样.一样计算指数位.也是分为以下步骤
1.转为科学计数法.
2.移动指数位.
3.计算指数位
4.尾数位补零到23位.
5.拼接进行二进制,并且二进制转为16进制.
1.转为科学计数法
-0.125 = 0.001
2.移动指数位
此时移动指数位是往小数点右边移动,移动到最高位为1的地方.
0.001 =>1.0 移动了三位,计算 -3. 往右边移动就是负数
1.0 则符号位是1代表负数. 指数位是负数.
3.计算指数位.
上面我们计算指数位是往小数点左边移动.所以指数位去相加.现在是往右边移动.所以相减
127-3 = 124 转为二进制 = 01111100
4.尾数位补零
0000 0000 0000 0000 0000 000
5.符号位 指数位 尾数位 进行拼接
1011 1110 0000 0000 0000 0000 0000 0000 (总共32位)
转为16进制
0xBE00 0000
所以-0.125 在内存中的16进制则是 0xBE000000
3.正数浮点16进制转为浮点数解析
我们会转换为16进制那么也要回转换回来
1.16进制拆分为2进制.
2.分出符号位 指数位 尾数位
3.求指数位是负数还是整数
4.移动指数位
比如我们的12.25f. 十六进制是x41440000
1.16进制转为2进制
0100 0001 0100 0100 0000 0000 0000 0000
2.分出符号位 指数位 尾数位
0 10000010 10001000000000000000000
3.求出指数位
指数位位 10000010 > 01111111 所以可以判断我们的小数是正数
10000010 - 01111111 = 130 - 127 = 3;
得出了我们要移动的位数
4.移动指数位
首先计算出的指数转为2进制 3 = 0011;
然后反过来.尾数位右移动三位.如下.
100010 >> 3 = 100.010 尾数的最高位不需要.所以补零
然后加上符号位.
符号位为0.代表是正数.所以+1
1100.010
再举个例子
7.25 在内存的16进制为0x40E8
1.16进制转为二进制
0100 0000 1110 1000 0000 0000 .....
2.计算指数位,尾数需要往右移动纪委
10000001 - 01111111 = 129 - 127 = 2;得出移动2位
3.移动尾数位
因为高位为0,所以代表我们转换的浮点数是正数.最后我们的高位要加上1才可以.
11010 ==>2位 = 11.010
符号位为0.所以高位补1
111.01 这个二进制在转换为10进制得出7.25
小数转为10进制:
.01是是两位. 分别记位 2的-1次方 2-2次方.
第一位计算: 0 * 1/2-1次方.
第二位计算: 1 * 1/2-2次方即可.
最后结果相加.
如果有三位.那么就是 用第三位数值 * 1/2-3次方即可.
01/2 + 1 1/4 = 0.25.所以我们可以推算出是0.25
4.Double类型解析.
double类型转换跟float一样.只不过指数位变成了11位. 剩余的42位表示尾数位.
2~11次方 - 1;就是用于计算的指数.也就是 1023.
三丶浮点汇编
1.浮点栈
因为有了浮点协处理器.所以浮点指令的操作有点不同.它是通过浮点寄存器来实现的.
浮点寄存器是通过栈结构来实现的.也称作浮点栈. 由 st(0) - st(7); 其中写st默认就是st(0)
操作任意浮点栈就需要加上序号 st(7);
值得注意的是浮点栈是循环栈. 也就是说st(0)出栈的数据.会放到st(7)中.这样依次使用.
2.浮点汇编
针对协处理器.也提供的相应的汇编进行操作.
分别是 fld类指令 fst 指令. 以及 fcom fadd等指令
都是大写
- 压栈指令
FLD IN 将浮点数IN 压入浮点栈
FILD IN 将整数压入浮点栈 mem32/64 80
FLDZ 默认压入0,浮点栈是0 -
出栈指令
FST OUT 将浮点栈顶(st(0))的值给OUT存储. out可以是 mem32/64,但是不出栈
FSTP OUT 同FST out保存值,但是会出栈.
FISTP OUT 出栈,并且以整数的形式给OUT存储. - 栈比较
也可以进行栈中的值比较.用来更改标志位.
FCOM IN 将IN地址的内容.与浮点栈顶比较(st(0));
FTST 比较栈顶(st(0)); 是否为空. -
浮点加法
FADD IN 将St(0)的数据于in做加法. 值保存在 栈顶st(0);中.
FADDP st(N),st 将st(n)栈中的数据于st(0)中的数据进行运算.浮点栈有7个.那么N的取值就是0~7;
先执行一次出栈冬枣.然后相加结果放在 st(0)中存储.
3.使用内联浮点汇编实现加法
- 浮点做加法
int main(int argc, char* argv[]) { float a = 11.25; float c = 12.35; float d = 13.25f; float b = 0.0f; __asm{ fld dword ptr[ebp - 0x4]; fld dword ptr[ebp - 0x8]; fld dword ptr[ebp - 0xc]; faddp st(1),st(0) fstp dword ptr[ebp - 0x10]; } printf("%f \r\n",b); return 0; } 实现结果:
- 浮点做返回值
float GetFloatValue() { return 12.25f; } int main(int argc, char* argv[]) { int value = GetFloatValue(); return 0; } 观看汇编,汇编分为两层.一层是调用内.一层是调用外.
调用内: 也就是GetFloatValue()函数内部.
push ebp mov ebp,esp sub esp,40h push ebx push esi push edi lea edi,[ebp-40h] mov ecx,10h mov eax,0CCCCCCCCh rep stos dword ptr [edi] fld dword ptr [__real@4@4002c400000000000000 (00423fd0)]
