在 SSE 中有一个函数 _mm_cvtepi32_ps(__m128i input)
接受 32 位宽有符号整数 (int32_t
) 的输入 vector 并将它们转换为 float
s.
现在,我想将输入整数解释为未签名。但是没有函数 _mm_cvtepu32_ps
并且我找不到一个实现。你知道我在哪里可以找到这样的功能或者至少给出实现的提示吗?
为了说明结果的差异:
unsigned int a = 2480160505; // 10010011 11010100 00111110 11111001
float a1 = a; // 01001111 00010011 11010100 00111111;
float a2 = (signed int)a; // 11001110 11011000 01010111 10000010
最佳答案
使用 Paul R 的解决方案和我之前的解决方案 四舍五入后的 float 与原整数之差小于等于 0.75 ULP(排在最后的单位)。在这些方法中 在两个地方可能会发生舍入:在 _mm_cvtepi32_ps 和 在 _mm_add_ps 中。这会导致某些输入的结果不是尽可能准确。
例如,使用 Paul R 的方法 0x2000003=33554435 被转换为 33554432.0,但是 33554436.0 也作为 float 存在,在这里会更好。 我以前的解决方案也存在类似的错误。 这种不准确的结果也可能出现在编译器生成的代码中,see here .
按照gcc的方法(see Peter Cordes' answer to that other SO question) ,得到0.5 ULP以内的准确转换:
inline __m128 _mm_cvtepu32_ps(const __m128i v)
{
__m128i msk_lo = _mm_set1_epi32(0xFFFF);
__m128 cnst65536f= _mm_set1_ps(65536.0f);
__m128i v_lo = _mm_and_si128(v,msk_lo); /* extract the 16 lowest significant bits of v */
__m128i v_hi = _mm_srli_epi32(v,16); /* 16 most significant bits of v */
__m128 v_lo_flt = _mm_cvtepi32_ps(v_lo); /* No rounding */
__m128 v_hi_flt = _mm_cvtepi32_ps(v_hi); /* No rounding */
v_hi_flt = _mm_mul_ps(cnst65536f,v_hi_flt); /* No rounding */
return _mm_add_ps(v_hi_flt,v_lo_flt); /* Rounding may occur here, mul and add may fuse to fma for haswell and newer */
} /* _mm_add_ps is guaranteed to give results with an error of at most 0.5 ULP */
注意其他高位/低位分区也是可以的,只要_mm_cvt_ps可以转换 两件都 float 而不四舍五入。 例如,具有 20 个高位和 12 个低位的分区将同样有效。
关于c - 如何使用 SSE 进行 uint32/float 转换?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34066228/