Я хочу преобразовать значение с плавающей запятой в 16-разрядное целое без знака без насыщения (вместо wrapparound/overflow).
#include <iostream>
#include <xmmintrin.h>
void satur_wrap()
{
const float bigVal = 99000.f;
const __m128 bigValVec = _mm_set1_ps(bigVal);
const __m64 outVec64 =_mm_cvtps_pi16(bigValVec);
#if 0
const __m128i outVec = _mm_movpi64_epi64(outVec64);
#else
#if 1
const __m128i outVec = _mm_packs_epi32(_mm_cvttps_epi32(bigValVec), _mm_cvttps_epi32(bigValVec));
#else
const __m128i outVec = _mm_cvttps_epi32(bigValVec);
#endif
#endif
uint16_t *outVals = NULL;
posix_memalign((void **) &outVals, sizeof(__m128i), sizeof(__m128i));
_mm_store_si128(reinterpret_cast<__m128i *>(outVals), outVec);
for (int i = 0; i < sizeof(outVec) / sizeof(*outVals); i++)
{
std::cout << "outVals[" << i << "]: " << outVals[i] << std::endl;
}
std::cout << std::endl
<< "\tbigVal: " << bigVal << std::endl
<< "\t(unsigned short) bigVal: " << ((unsigned short) bigVal) << std::endl
<< "\t((unsigned short)((int) bigVal)): " << ((unsigned short)((int) bigVal)) << std::endl
<< std::endl;
}
Пример выполнения:
$ ./row
outVals[0]: 32767
outVals[1]: 32767
outVals[2]: 32767
outVals[3]: 32767
outVals[4]: 32767
outVals[5]: 32767
outVals[6]: 32767
outVals[7]: 32767
bigVal: 99000
(unsigned short) bigVal: 65535
((unsigned short)((int) bigVal)): 33464
Оператор ((unsigned short)((int) bigVal))
работает по желанию (но, вероятно, UB, правильно?). Но я не могу найти нечто подобное с SSE. Я должен что-то пропустить, но я не смог найти примитив для преобразования четырех 32-разрядных float
в четыре 32-битных int
s.
EDIT: Ой, я полагал, что это будет "нормальным" для 32-разрядного целочисленного → 16-разрядного беззнакового целочисленного преобразования для использования wraparound. Но с тех пор я узнал, что _mm_packs_epi32
использует unsigned-saturate (и не существует _mm_packus_epi32
). Есть ли способ установить режим или другой примитив, кроме _mm_packus_epi32
?