加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c – 如何使用SSE / AVX有效地执行double / int64转换?

发布时间:2020-12-16 05:28:52 所属栏目:百科 来源:网络整理
导读:SSE2具有在单精度浮点和32位整数之间转换向量的指令. _mm_cvtps_epi32() _mm_cvtepi32_ps() 但是没有双精度和64位整数的等价物.换句话说,他们缺少: _mm_cvtpd_epi64() _mm_cvtepi64_pd() 似乎AVX也没有. 什么是模拟这些内在函数的最有效的方式? 解决方法
SSE2具有在单精度浮点和32位整数之间转换向量的指令.

> _mm_cvtps_epi32()
> _mm_cvtepi32_ps()

但是没有双精度和64位整数的等价物.换句话说,他们缺少:

> _mm_cvtpd_epi64()
> _mm_cvtepi64_pd()

似乎AVX也没有.

什么是模拟这些内在函数的最有效的方式?

解决方法

如果您愿意削减角落,请双击“ – ” int64转换只能在两个指令中完成:

>如果你不在乎无限或NaN.
>对于双重 – int64_t,你只关心范围[-2 ^ 51,2 ^ 51]中的值.
>对于双重 – uint64_t,你只关心[0,2 ^ 52]范围内的值.

双 – > uint64_t中

//  Only works for inputs in the range: [0,2^52)
__m128i double_to_uint64(__m128d x){
    x = _mm_add_pd(x,_mm_set1_pd(0x0010000000000000));
    return _mm_xor_si128(
        _mm_castpd_si128(x),_mm_castpd_si128(_mm_set1_pd(0x0010000000000000))
    );
}

双 – >的int64_t

//  Only works for inputs in the range: [-2^51,2^51]
__m128i double_to_int64(__m128d x){
    x = _mm_add_pd(x,_mm_set1_pd(0x0018000000000000));
    return _mm_sub_epi64(
        _mm_castpd_si128(x),_mm_castpd_si128(_mm_set1_pd(0x0018000000000000))
    );
}

uint64_t – >双

//  Only works for inputs in the range: [0,2^52)
__m128d uint64_to_double(__m128i x){
    x = _mm_or_si128(x,_mm_castpd_si128(_mm_set1_pd(0x0010000000000000)));
    return _mm_sub_pd(_mm_castsi128_pd(x),_mm_set1_pd(0x0010000000000000));
}

int64_t – >双

//  Only works for inputs in the range: [-2^51,2^51]
__m128d int64_to_double(__m128i x){
    x = _mm_add_epi64(x,_mm_castpd_si128(_mm_set1_pd(0x0018000000000000)));
    return _mm_sub_pd(_mm_castsi128_pd(x),_mm_set1_pd(0x0018000000000000));
}

舍入行为:

>对于双 – > uint64_t转换,舍入在当前四舍五入模式后正常工作. (通常是圆均匀的)
>对于双 – > int64_t转换,除了截断之外,舍入将遵循所有模式的当前舍入模式.如果当前四舍五入模式被截断(向零舍入),它将实际上向负无穷大.

它是如何工作的?

尽管这个技巧只有2条指令,但并不完全不言自明.

关键是要认识到对于双精度浮点,范围[2 ^ 52,2 ^ 53]中的值具有正好位于尾数最低位的“二进制位置”.换句话说,如果你清除指数和符号位,尾数就变成了整数表示.

要将x从double转换为> uint64_t,你添加的魔术数字M是浮点值2 ^ 52.这将x置于[2 ^ 52,2 ^ 53]的“归一化”范围内,并且方便地舍弃小数部分位.

现在剩下的就是删除高12位.这很容易通过掩蔽它来完成.最快的方法是认识到那些高12位与M的相同.所以我们可以简单地减去XOR或者XOR,而不是引入额外的掩码常数.XOR具有更多的吞吐量.

从uint64_t转换为>这个过程恰恰相反.您返回M的指数位.然后通过在浮点中减去M来对数字进行非归一化.

由于您需要处理2的补码符号扩展,因此签名的整数转换稍微复杂一些.我会把这些作为读者的练习.

相关:A fast method to round a double to a 32-bit int explained

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读