fxtract
дает вам показатель степени 2, как сказал @Jester в комментариях.
Чтобы получить основание степени 10, вы должны знать о логарифмах. Вы вычисляете логарифм по основанию 10 ввода, а затем усекаете его до целого числа. В x87 fldlg2
дает log10(x), тогда fyl2x
может рассчитать логарифм как
- log10(x) = log10(2) log2(x)
Чтобы усечь его до целого числа, вы устанавливаете x87 для округления до нуля (путем or
вставки 0x0c000 в управляющее слово) и используете frndint
.
Чтобы вычислить мантиссу, вы делите ввод на степень 10. Обычный способ получить степень 10 — использовать степени 2 и 5, используя целочисленная арифметика для степени 5 (как в pow5mult Дэвида М. Гея) и масштабирование экспоненты с плавающей запятой для степеней двойки. Более простой, но, возможно, более медленный или менее точный способ — использовать x87 и формулу
- 10p = 2m = 2r 2m - r, где m = log2 sub> 10 p и r = раунд (м)
В x87 fldl2t
обеспечивает log2(10). f2xm1
вычисляет 2x - 1, если x — дробь от -1 до 1. fscale
умножает на 2r, если 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
, чтобы запустить это в gdb на OpenBSD/amd64.
$ 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
person
George Koehler
schedule
08.01.2018
123.45=1.92890625*2^6
. - person Jester   schedule 15.06.2017call ftoa
:-) См. также: stackoverflow.com/questions/17632150/turn-float-into-string, stackoverflow.com/questions/22962040/ и stackoverflow.com/questions/10912128/ - person Cody Gray   schedule 16.06.2017ftoa
- это стандартная библиотечная функция C? - person Michael Petch   schedule 16.06.2017