每种编程语言都有自己的方法将整数转换为浮点数,将01010转换为其他01010。 如果您看到ASM生成的代码,它会使用协处理器指令向用户隐藏真实值。
但它如何在真实中发挥作用?如何计算尾数,指数算法?
答案 0 :(得分:4)
如果你知道浮点格式,你应该能够自己计算出算法。
由于此问题已标记为assembly,因此以下是x86的示例实现:
int_to_float:
xor eax, eax
mov edx, [esp+4]
test edx, edx
jz .done
jns .pos
or eax, 0x80000000 ; set sign bit
neg edx
.pos:
bsr ecx, edx
; shift the highest bit set into bit #23
sub ecx, 23
ror edx, cl ; works for cl < 0 too
and edx, 0x007fffff ; chop off highest bit
or eax, edx ; mantissa
add ecx, 127 + 23 ; bias
shl ecx, 23
or eax, ecx ; exponent
.done:
ret
注意:这会返回eax
中的float,而调用约定通常会强制st0
。我只是想完全避免使用FPU代码。
答案 1 :(得分:2)
当将整数转换为浮点数时,它只是移动直到尾数在正确的范围内,即1 <1。 m&lt; 2,指数就是它移动了多少步。
例如,数字1010
会移动到1.010
,指数为3
,因为它是移位的位数。
尾数的第一个数字,即小数分隔符前的1
,不会存储在数字中,因为它总是一个。 (零值被视为一个单独的案例。)
expontent(对于双精度数)存储的偏移量为1023(001111111111),因此expontent 3存储为1026(010000000010)。
这使得1010
的表示形式为双精度浮点数:
010000000010 010 0000000000000000000000000000000000000000000000000
010
之后的所有零都是填充52位尾数的其余部分。
您可以在此处阅读有关浮点格式的更多信息:
Wikipedia: Double-precision floating-point format
答案 2 :(得分:0)
对于32位int
,64位int64
和IEEE 64位double
,以下技巧有效(除了违反别名规则等):
double convert(int x) {
double tricky = 0x1.8p53;
int64 hack = (int64 &)tricky + x;
return (double &)hack - 0x1.8p53;
}
我在这里tricky = 2^53 + 2^52
。此值中可表示的最小变化为1
,表示有效数以1
为单位进行测量。有效数存储在double
的低位52位中。通过向x
添加x
,我不会溢出或下溢有效数字(因为hack
是32位),因此2^53 + 2^52 + x
是double
的二进制表示形式一个2^53 + 2^52
。减去x
给我double
,但作为movsx rax, dword ptr [x]
add rax, [tricky]
mov [hack], rax
fld [hack]
fsub st(0), [tricky]
fstp [answer]
。
(接下来,我认为,接近于x86-64汇编代码。我不明白为什么它不会做正确的事情,但我还没有对它进行测试。或者甚至组装了它。)
{{1}}