由于“_mm_sign_ps”不存在,因为我能够找到:给定一个带有四个浮点值的__m128值,哪条SIMD指令或SIMD指令列表将其转换为__m128值,其中四个浮点值 - 点值包含:
+1,如果四个原始值为正且大于零。 0,如果四的原始值为零。 -1,如果四个原始值为负且小于零。
答案 0 :(得分:3)
SSE真的不太匹配。首先,比较函数不会导致±1.0f,而是在条件为真时设置所有位,或者如果条件为假则不设置任何位。此外,您要求进行三向比较,如果值为“零”,则结果为“零”(“零”在引号中,因为您实际上没有指定是否需要正零或负零; IEEE 754有两个)。如果您可以重新设置问题以更好地匹配SSE提供的内容,那么您将 更好。
那说:
__m128 foo (__m128 value) {
const __m128 zero = _mm_set_ps1 (0.0f);
__m128 positives = _mm_and_ps(_mm_cmpgt_ps (value, zero), _mm_set_ps1(1.0f));
__m128 negatives = _mm_and_ps(_mm_cmplt_ps (value, zero), _mm_set_ps1(-1.0f));
return _mm_or_ps(positives, negatives);
}
我不知道您计划使用它的目的是什么,但如果您对按位操作感到满意,那么很有可能您可以弄清楚如何使用单_mm_cmpgt_ps
,{ {1}},_mm_cmpge_ps
或_mm_cmplt_ps
。
答案 1 :(得分:1)
SSE没有自然/有效地以这种方式为浮动/双重工作。您希望对-1.0f
/ 0.0f
/ 1.0f
sgn(x)值做什么?
您应该优化在寄存器中实际具有这些FP值的步骤,并直接使用比较掩码结果。您提出的问题是an X-Y problem的标志。是的,你实际上可以实现这一点,但通常你不应该。
例如,您可以使用布尔AND或比较+ AND来获取符号位的掩码,然后可以使用布尔XOR(_mm_xor_ps()
)来翻转设置了这些位的另一个向量中的符号位,以及保持在相应元素中未设置符号位的元素保持不变。
(FP否定就像翻转符号位一样简单,因为IEEE-754二进制格式使用符号/幅度表示。)
但请注意-0.0
,因为它设置了符号位。如果你想根据相应的元素归零而忽略其他元素,你可以使用几个布尔运算,然后使用_mm_cmpeq_ps
的结果屏蔽结果0.0。 (0.0和-0.0都适用。)
例如:
// SSE2 v * sgn(src), except we treat src=NaN as src=0
__m128 mul_by_signum(__m128 v, __m128 src)
{
__m128 signbits = _mm_and_ps(src, _mm_set1_ps(-0.0)); // epi32(1<<31)
__m128 flipped = _mm_xor_ps(v, signbits);
__m128 nonzero = _mm_cmpne_ps(src, _mm_setzero_ps());
return _mm_and_ps(flipped, nonzero);
}
对于整数,有SSSE3 psignb/w/d
,它将保留/归零/否定目标中的元素,具体取决于源为正/零/负。目的地为_mm_set1_epi32(1)
,它会为您提供1/0 / -1元素的向量。
您无法在FP数据上使用它,因为FP使用符号/幅度而不是2的补码。并且因为它检查整数零,所以-0.0
看起来像一个负数。