浮動小数点値を飽和せずに 16 ビットの符号なし整数に変換したい (代わりにラップアラウンド/オーバーフロー)。
#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 と非常によく似たものを見つけることができません。float
何かが欠けているに違いありませんが、4 つの 32 ビットを 4 つの 32ビットに変換するプリミティブが見つかりませんでしたint
。
編集: おっと、32 ビット整数 -> 16 ビット符号なし整数変換でラップアラウンドを使用するのは「通常」だと思いました。しかし、私はそれ以来、_mm_packs_epi32
符号付き飽和を使用していることを知りました (そして、 はないよう_mm_packus_epi32
です)。モードまたは別のプリミティブを設定する方法はあります_mm_packus_epi32
か?