FXTRACT指令示例

时间:2017-06-15 15:56:50

标签: assembly x86 x87

我在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 = 123456fexp = -3 或类似:fsig = 1.23456fexp = 3 那么,我错过了什么?

1 个答案:

答案 0 :(得分:3)

fxtract给出了指数基数2,正如@Jester在评论中所说的那样。

  • 123.456 = 1.929×2 6

要获得指数基数10,您必须了解对数。您计算输入的对数基数10,然后将其截断为整数。在x87中,fldlg2给出log 10 (x),然后fyl2x可以calculate the logarithm

  • log 10 (x)= log 10 (2)×log 2 (x)

要将其截断为整数,可将x87设置为舍入为零(通过or将0x0c000转换为控制字)并使用frndint

要计算有效数,可以将输入除以10的幂。获得10的幂的习惯方法是使用2和5的幂,使用integer arithmetic获得5的幂(如{ {3}}),并将浮点指数缩放为2的幂。更简单但可能更慢或更不准确的方法是使用x87和公式

  • 10 p = 2 m = 2 r ×2 m - r 其中m = log 2 10×p且r = round(m)

在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

我添加了标签mainint 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