c - 如何使用 SSE 进行 uint32/float 转换?

标签 c x86 sse simd

在 SSE 中有一个函数 _mm_cvtepi32_ps(__m128i input) 接受 32 位宽有符号整数 (int32_t) 的输入 vector 并将它们转换为 floats.

现在,我想将输入整数解释为未签名。但是没有函数 _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/

相关文章:

visual-c++ - 如何让 VC 编译器更好地优化我的 SIMD 代码?

c++ - 使用 OpenMP 与 Affinity 调度进行软件并行化?

assembly - 如何将第9扇区复制到第1扇区?

assembly - 为了流水线,实际的 Intel x86 处理器有多少开销?

assembly - 为什么对非核心响应/非核心请求的需求过多?

visual-studio-2010 - 如何在Visual Studio 2010中添加与SIMD相关的编译器标志

C 代码,为什么将地址 0xFF00 转换为结构?

c++ - 使用 C 进行套接字编程时无法接收或发送整个数据包

c++ - sscanf 从八进制转换 : How does it know?

performance - SSE 4.2 CSV 文件解析