Documente noi - cercetari, esee, comentariu, compunere, document
Documente categorii

Conversia floating-point to integer

CONVERSIA FLOATING-POINT TO INTEGER


O mare parte din biblioteci pun la dispozitie rutine pentru conversia de tipul float-to-integer a valorilor in virgula mobila. Multe dintre aceste biblioteci se conformeaza standardelor de codificare ANSI C care impun ca regula de rotunjire sa fie trunchierea. Pentru instructiunea FIST regula implicita (default) de rotunjire este cea de routunjire la par, de aceea multi scriitori de cod pentru compilatoare implementeaza o modificare a regulii de rotunjire in procesor, cu scopul de a se conforma standardelor C si FORTRAN. Aceasta implementare necesita modificarea byte-ului control utilizand instrutiunea fldcw. Aceasta instructiune este o instructiune de sincronizare si va cauza o puternica scadere a performantei aplicatiei peprocesoarele Pentium, Pentium Pro and Pentium II.



La implementarea unei aplicatii, trebuie luat in considerare daca obtinerea unui rezultat in virgula mobila este important sau nu. In caz negativ, pentru evitarea sincronizarii si a supraincarcarii instructiunii fldcw.

Pentru evitarea modificarii regulii de rotunjire se va folosi urmatorul algoritm:


_ftol32proc

lea ecx,[esp-8]

sub esp,16                     ; allocate frame

and ecx,-8                     ; align pointer on boundary of 8

fld st(0)     ; duplicate FPU stack top

fistp qword ptr[ecx]

fild qword ptr[ecx]

mov edx,[ecx+4]                         ; high dword of integer

mov eax,[ecx]               ; low dword of integer

test eax,eax

je integer_QNaN_or_zero

arg_is_not_integer_QNaN:

fsubp st(1),st                ; TOS=d-round(d),


test edx,edx                  ; what's sign of integer

jns positive



; number is negative

; dead cycle

; dead cycle

fstp dword ptr[ecx]      ; result of subtraction

mov ecx,[ecx]               ; dword of difference(single precision)

add esp,16

xor ecx,80000000h

add ecx,7fffffffh           ; if difference>0 then increment integer

adc eax,0 ; inc eax (add CARRY flag)

ret

positive:

fstp dword ptr[ecx]      ;17-18 ; result of subtraction

mov ecx,[ecx]               ; dword of difference (single precision)

add esp,16

add ecx,7fffffffh           ; if difference<0 then decrement integer

sbb eax,0 ; dec eax (subtract CARRY flag)

ret

integer_QNaN_or_zero:

test edx,7fffffffh

jnz arg_is_not_integer_QNaN

add esp,16

ret