如何用AVX2高效实现Int128与Double转换及宽范围位置表示
我正在开发一款支持用户在超大空间范围(直径至少100万光年)内移动的软件,要求位置表示精度不低于0.1毫米,计划采用128位定点数(fixed128)存储位置。但距离、开方、除法、积分等数学运算更适合用双精度(double)或单精度浮点数处理——通常是对两个int128坐标相减得到相对距离,此时差值足够小不会损失过多精度;而差值大的场景对精度要求也较低。
在实现fixed128时,我遇到了核心问题:如何利用AVX2 SIMD指令集快速实现int128与double的双向转换?(AVX512普及度不足,无法在该软件中使用)
已尝试方案
我参考过关于SSE/AVX下高效实现double/int64转换的方案,其中Wim的思路是将int64拆分为小于52位的尾数部分,拼接指数位后通过浮点运算还原成double,这种方式效率较高。
基于此思路,我尝试将由两个uint64(ilow和ihigh)组成的uint128拆分为三部分:
- v_lo:ilow的低48位;
- v_mi:ilow的高16位 + ihigh的低16位;
- v_hi:ihigh的高48位;
v_lo和v_hi的转换可以参考Wim的uint64_to_double_fast_precise方法,但v_mi的转换需要4条指令,比v_lo和v_hi的指令数之和(1+2)还多。我怀疑可以通过permute/shuffle/unpack等混洗指令组合实现更高效的转换,但对这类指令的使用不太熟悉。
现有ufixed128转double代码
constexpr auto fix128_frac_bits = 32; __m256d ufixed128_to_double_fast(const __m256i& ihigh, const __m256i& ilow) { //constants __m256d magic_d_hm = _mm256_set1_pd(pow(2.0, 52 + 48 - fix128_frac_bits) + pow(2.0, 52 + 80 - fix128_frac_bits)); __m256d magic_d_lo = _mm256_set1_pd(pow(2.0, 52 - fix128_frac_bits)); __m256i magic_i_lo = _mm256_castpd_si256(magic_d_lo); __m256i magic_i_mi = _mm256_castpd_si256(_mm256_set1_pd(pow(2.0, 52 + 48 - fix128_frac_bits))); __m256i magic_i_hi = _mm256_castpd_si256(_mm256_set1_pd(pow(2.0, 52 + 80 - fix128_frac_bits))); //majik operations __m256i v_lo = _mm256_blend_epi16(ilow, magic_i_lo, 0b10001000); __m256i v_mi = _mm256_slli_epi64(ihigh, 16); __m256i losr48 = _mm256_srli_epi64(ilow, 48); v_mi = _mm256_xor_si256(v_mi, losr48); v_mi = _mm256_blend_epi32(magic_i_mi, v_mi, 0b01010101); __m256i v_hi = _mm256_srli_epi64(ihigh, 16); v_hi = _mm256_xor_si256(v_hi, magic_i_hi); //final fp __m256d loresult = _mm256_sub_pd(_mm256_castsi256_pd(v_lo), magic_d_lo); __m256d result = _mm256_sub_pd(_mm256_castsi256_pd(v_hi), magic_d_hm); result = _mm256_add_pd(result, _mm256_castsi256_pd(v_mi)); result = _mm256_add_pd(result, loresult); return result; }
补充说明
我已实现有符号fixed128转double的功能,只需在magic_d_hm和magic_i_hi中加入2.0^(127 - fix128_frac_bits)即可。但目前还没有高效的double转int128/uint128实现——我能通过位运算实现比C++ static_cast更快的标量转换,但远不如上述转换高效,且需要占用大量寄存器存储常量。
需求帮助
- 优化AVX2下int128与double的双向转换效率;
- 若当前方案不可行,提供替代的宽范围高精度位置表示方案(排除浮点原点/浮点网格方案,因其物理计算不稳定、上层实现复杂或难以AVX加速)。
注:我计划在完成fixed128和double-double的高度优化后对比性能,再决定使用哪种方案。当前代码托管于个人代码仓库。
内容的提问来源于stack exchange,提问作者Velctor

