我在NASM中编写了这段代码:
section .data
fvar: dd 123.456
fsig: dq 0.0
fexp: dq 0.0
section .text
fld dword[fVar]
fxtract ; put significand in ST(0), and exponent in ST(1)
fstp qword[fsig] ; fsig = 1.929
fstp qword[fexp] ; fexp = 6
我等着找:fsig = 123456
和fexp = -3
或类似:fsig = 1.23456
和fexp = 3
那么,我错过了什么?
答案 0 :(得分:3)
fxtract
给出了指数基数2,正如@Jester在评论中所说的那样。
要获得指数基数10,您必须了解对数。您计算输入的对数基数10,然后将其截断为整数。在x87中,fldlg2
给出log 10 (x),然后fyl2x
可以calculate the logarithm为
要将其截断为整数,可将x87设置为舍入为零(通过or
将0x0c000转换为控制字)并使用frndint
。
要计算有效数,可以将输入除以10的幂。获得10的幂的习惯方法是使用2和5的幂,使用integer arithmetic获得5的幂(如{ {3}}),并将浮点指数缩放为2的幂。更简单但可能更慢或更不准确的方法是使用x87和公式
在x87中,fldl2t
提供log 2 (10)。 f2xm1
计算2 x - 1如果x是介于-1和1之间的分数。fscale
乘以2 r ,如果r是整数。
代码是
section .data
fvar: dd 123.456
fsig: dq 0.0
fexp: dq 0.0
section .bss
newcw: resw 1
oldcw: resw 1
section .text
global main
main:
fld dword[fvar]
;; fexp = truncate(log_10(fvar))
fld st0
fldlg2
fxch st1 ; st2 = fvar, st1 = log_10(2), st0 = fvar
fyl2x ; log_10(fvar) = log_10(2) * log_2(fvar)
fstcw [oldcw]
mov dx, [oldcw]
or dx, 0x0c000 ; rounding mode = 3, toward zero
mov [newcw], dx
fldcw [newcw]
frndint ; truncate log_10(fvar)
fldcw [oldcw] ; restore old rounding mode
fst qword[fexp]
;; fsig = fvar / 10^(fexp)
fldl2t ; st2 = fvar, st1 = fexp, st0 = log_2(10)
fmulp ; m = log_2(10) * fexp
fld st0
frndint ; integral part of m
fxch st1 ; st2 = fvar, st1 = integer, st0 = m
fsub st0, st1 ; fractional part of m
f2xm1
fld1
faddp ; 2^(fraction)
fscale ; 10^fexp = 2^(integer) * 2^(fraction)
fstp st1 ; st1 = fvar, st0 = 10^fexp
fdivp ; fvar / 10^fexp
fstp qword[fsig]
int 3
我添加了标签main
和int 3
,因此我可以在OpenBSD / amd64上的gdb中运行它。
$ nasm -felf64 float10.s && gcc -nopie -o float10 float10.o
$ gdb float10
...
(gdb) run
...
Program received signal SIGTRAP, Trace/breakpoint trap.
...
(gdb) x/1wf &fvar
0x601000 <fvar>: 123.456001
(gdb) x/1wg &fsig
0x601004 <fsig>: 1.2345600128173828
(gdb) x/1wg &fexp
0x60100c <fexp>: 2