|
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