我正在尝试使用用C编写的printTime()函数来测试 32位 NASM程序的运行时间。
void printTime(float time){
printf("The cpu time is %e \n" , time);
}
以下是NASM代码的一部分:
push edi <---------------- Here edi holds int 6580001
call printTime
pop edi
以下是GCC生成的汇编代码,我使用GDB跟踪每一步:
push ebp
mov esp, ebp
sub 0x8, esp
flds 0x8(esp) <------- x/d ($esp+0x8) gives me 6580001, the correct number
sub 0x4,esp
lea -0x8(esp),esp
fstpl (esp)
push 0x80486f6
call 0x8048370 <printf@plt> <--- it prints 9.220545e-39 here, which is wrong
add 0x10, esp
leave
ret
任何人都可以告诉我为什么printf函数打印错误而不是6.58001e + 5?我很感激。
答案 0 :(得分:1)
您正在将一个整数加载到浮点寄存器中,并期望它在浮点中被视为相同的值。这不是IEEE754浮点的工作原理,数字使用不同的编码方案。
由整数6580001
(0x00646701
)形成的位模式如下面的分析图所示。浮点数由符号,偏置指数和小数部分组成。
seee eeee efff ffff ffff ffff ffff ffff
0000-0000 0110-0100 0110-0111 0000-0001
首先,让我们处理这个标志。成为0
,这意味着数字是正数。这很容易: - )
指数位全为零,在IEEE754编码中,您通常会减去127
的偏差,并将该幂提高两倍以获得乘数。
但是,特殊处理全零指数(这些是非规范化数字)。首先,没有完成向分数位添加一个的常规做法(见下文)。其次,将乘数调整为2-126
而不是2-127
。
这使得乘数1.1754943508222875079687365372222 x 10-38
。
对于小数位,通常会添加一个带有它们的位置值(减少2的倒数)但是,由于它是非规范化的,你跳过添加一个:
110-0100 0110-0111 0000-0001
|| | || ||| |
|| | || ||| +- 1/8M = 0.00000011920928955078125
|| | || ||| (64K-4M)
|| | || ||+----------- 1/32K = 0.000030517578125
|| | || |+------------ 1/16K = 0.00006103515625
|| | || +------------- 1/8K = 0.0001220703125
|| | || (2K,4K)
|| | |+----------------- 1/1K = 0.0009765625
|| | +------------------ 1/512 = 0.001953125
|| | (64-256)
|| +----------------------- 1/32 = 0.03125
|| (8,16)
|+--------------------------- 1/4 = 0.25
+---------------------------- 1/2 = 0.5
0.78439342975616455078125
要获取实际号码,您可以获取该结果的乘积和之前计算的乘数,得到9.2205004550049022573489420224302 x 10-39
,这是您所看到的结果。