Я предполагаю, что требуется усечение, так же, как если бы вы написали i = (int)f
в "C".
Если у вас SSE3, вы можете использовать:
int convert(float x)
{
int n;
__asm {
fld x
fisttp n // the extra 't' means truncate
}
return n;
}
Альтернативно, с SSE2 (или в x64, где встроенная сборка может быть недоступна), вы можете использовать почти так же быстро:
#include <xmmintrin.h>
int convert(float x)
{
return _mm_cvtt_ss2si(_mm_load_ss(&x)); // extra 't' means truncate
}
На старых компьютерах есть возможность установить режим округления вручную и выполнить преобразование с помощью обычной инструкции fistp
. Это, вероятно, будет работать только для массивов с плавающей запятой, в противном случае следует позаботиться о том, чтобы не использовать какие-либо конструкции, которые заставили бы компилятор изменить режим округления (например, приведение). Это делается так:
void Set_Trunc()
{
// cw is a 16-bit register [_ _ _ ic rc1 rc0 pc1 pc0 iem _ pm um om zm dm im]
__asm {
push ax // use stack to store the control word
fnstcw word ptr [esp]
fwait // needed to make sure the control word is there
mov ax, word ptr [esp] // or pop ax ...
or ax, 0xc00 // set both rc bits (alternately "or ah, 0xc")
mov word ptr [esp], ax // ... and push ax
fldcw word ptr [esp]
pop ax
}
}
void convertArray(int *dest, const float *src, int n)
{
Set_Trunc();
__asm {
mov eax, src
mov edx, dest
mov ecx, n // load loop variables
cmp ecx, 0
je bottom // handle zero-length arrays
top:
fld dword ptr [eax]
fistp dword ptr [edx]
loop top // decrement ecx, jump to top
bottom:
}
}
Обратите внимание, что встроенная сборка работает только с компиляторами Microsoft Visual Studio (и, возможно, Borland), ее необходимо переписать в сборку GNU для компиляции с gcc.
Однако решение SSE2 со встроенными функциями должно быть достаточно переносимым.
Другие режимы округления возможны с помощью других встроенных функций SSE2 или путем ручной установки управляющего слова FPU в другой режим округления.