【发布时间】:2012-08-25 03:23:45
【问题描述】:
我想将浮点值转换为不饱和的 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 非常相似的东西。我一定遗漏了什么,但我找不到将四个 32 位 floats 转换为四个 32 位 ints 的原语。
编辑:糟糕,我认为 32 位整数 -> 16 位无符号整数转换使用环绕是“正常的”。但我后来了解到_mm_packs_epi32 使用有符号饱和(而且似乎没有_mm_packus_epi32)。除了_mm_packus_epi32之外,有没有办法设置模式或其他原语?
【问题讨论】:
-
顺便说一下,
_mm_store_si128可能无法正常工作,因为outVals可能不是 16 字节对齐的。将_mm_storeu_si128用于未处理负载或注意outVals的正确对齐。 -
是的,抱歉,在我的示例中忘记了 posix_memalign。
-
见:
CVTTPS2DQ又名_mm_cvttps_epi32 -
嘿@PaulR,看起来它会完美运行!让它成为一个答案,我会选择它。
-
@Brian:没问题 - 评论现在转换为答案。
标签: c++ c performance sse