【问题标题】:convertion of four packed single precision floating point to unsigned double words in x86-SSE在 x86-SSE 中将四个压缩单精度浮点转换为无符号双字
【发布时间】:2021-02-11 23:14:46
【问题描述】:

在带有 SSE 扩展的 x86 中,有没有办法将四个压缩单精度浮点值转换为四个双字? 最接近的指令是 CVTPS2PI,但它不能在两个 xmm 寄存器上执行,而应以CVTPS2PI MM, XMM/M64 给出。如果我想要<conversion_mnemonic> XMM, XMM/M128 之类的东西怎么办?

谢谢。 伊曼。

【问题讨论】:

  • 结果应该是整数类型吗?
  • 或许可以试试cvtps2dq
  • 感谢@fuz。 cvtps2dq 将完成这项工作,但要四个压缩的有符号双字。你知道无符号双字类型的类似指令吗?
  • 如果你想要无符号整数,你应该在你的问题中指定。另外,你想要什么舍入和溢出行为?
  • 谢谢@chtz。四舍五入:四舍五入到最接近的整数。溢出:实际上我没有使用大浮点数,它们都是正数,所以没关系。

标签: assembly x86-64 sse floating-point-conversion sse3


【解决方案1】:

x86 在 AVX512 之前没有对 FPunsigned 的原生支持,使用 vcvtps2udq (https://www.felixcloutier.com/x86/vcvtps2udq)。对于标量,您通常只需转换为 64 位有符号 (cvtss2si rax, xmm0) 并取其低 32 位(在 EAX 中),但这不是 SIMD 的选项。

如果没有 AVX-512,理想情况下,您可以使用签名转换 (cvtps2dq) 并获得相同的结果。即如果你的浮点数是非负数并且INT_MAX (2147483647.0)。

有关相关的 double->uint64_t 转换,请参见 How to efficiently perform double/int64 conversions with SSE/AVX?。如果需要的话,全频的应该可以从 double->uint64_t 适应到 float->uint32_t。

另一种可能性(对于 32 位 float->uint32_t)只是范围转移到有符号的 FP,然后以整数形式返回。 INT32_MIN ^ convert(x + INT32_MIN)。但这引入了小整数的 FP 舍入,因为 INT32_MIN 在 -224 .. 224 范围之外,float 可以表示每个整数。例如5 将在转换期间四舍五入到最接近的 28 倍数。所以那是不可用的;您需要尝试直接转换和范围移位转换,并且只有在直接转换给您0x80000000 时才使用范围移位转换。 (也许使用直接转换结果作为 SSE4 blendvps 的混合控制?)


对于 float->int32_t 的打包转换,有 SSE2 cvtps2dq xmm, xmm/m128 docs。 (cvttps2dq 将截断向 0 转换,而不是当前的默认舍入模式(最近的,如果你没有改变它)。

任何小于 -0.5 的负浮点数都将转换为整数 -1 或更低;作为uint32_t,该位模式代表了一个巨大的数字。超出 -231..231-1 范围的浮点数将转换为 0x80000000,英特尔的“整数不定”值。


如果你没有找到,只有 cvtps2pi 签名转换成 MMX 寄存器,你需要更好的地方去搜索:

【讨论】:

  • 如果输入大于2**31,你可以从浮点数中减去2**32(除了cvtps2dq之外还有一个comp+and+sub)
  • @chtz:对于大浮点数减去2**32 有什么好处,而不是像我建议的INT32_MIN ^ convert(x + INT32_MIN) 那样使用2**31? uint32 范围的上半部分是2**31 .. 2**32 - 1,因此减去 2^31 永远不会增加任何大于 2^31 的输入的幅度,因此不会进行更多舍入。
  • 你不会有任何舍入问题(因为值 >=2**31 将映射到 [-2**31, 0] 中的值,所以你只需要一次转换。减去 2**32 会自动给出正确的环绕就像进行了无符号转换一样(除非输入大于UINT32_MAX)。
  • @chtz:哦,我明白了,2**32 的整数加法是无操作的。是的,这是个好主意。 edit我的回答,如果你喜欢,或者发布你自己的。我的回答主要集中在当您的数字不是负数且不是很大时可以使用签名转换的点;单独的答案可能最适合实际工作的全范围转换方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-06-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-26
  • 1970-01-01
相关资源
最近更新 更多