【问题标题】:How to compare __m128 types?如何比较__m128类型?
【发布时间】:2011-08-27 21:30:43
【问题描述】:
__m128 a;
__m128 b;

a != b如何编码?

使用什么:_mm_cmpneq_ps_mm_cmpneq_ss

结果如何处理?

找不到足够的文档。

【问题讨论】:

  • 我希望你明白为什么比较浮点值的相等/不相等不是一个好主意? (这适用于标量代码和 SIMD 代码。)
  • 文档可从 Intel 和 AMD 获得。查找处理器手册。
  • @Paul R:SIMD 代码不一定是浮点数。
  • @Dietrich:我知道,但在这种特殊情况下。

标签: x86 sse simd


【解决方案1】:

您可能应该使用_mm_cmpneq_ps。然而,SIMD 代码与标量代码的比较解释略有不同。你想测试 any 对应的元素不相等吗?还是所有对应的元素不相等?

要测试来自 _mm_cmpneq_ps 的 4 次比较结果,您可以使用 _mm_movemask_epi8

请注意,比较浮点值是否相等通常不是一个好主意,除非在非常特殊的情况下。

__m128i vcmp = (__m128i)_mm_cmpneq_ps(a, b); // compare a, b for inequality
uint16_t test = _mm_movemask_epi8(vcmp); // extract results of comparison
if (test == 0xffff)
    // *all* elements not equal
else if (test != 0)
    // *some* elements not equal
else
    // no elements not equal, i.e. all elements equal

对于您需要英特尔提供的这两卷的文档:

Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 2A: Instruction Set Reference, A-M

Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 2B: Instruction Set Reference, N-Z

【讨论】:

  • 顺便说一句,在 Visual Studio 中,常规 C++ 强制转换不起作用,但您仍然可以使用内部 _mm_castps_si128 强制转换为 __m128i
  • @Virgil:是的,这只是 Visual Studio C/C++ 编译器和 SSE 代码的几个问题领域之一 - 还有一些令人讨厌的(并且看似随意的)ABI 限制。我建议使用 gcc 或更好的英特尔 ICC,并尽可能避免使用 Windows。 ;-)
  • 您通常希望在此处使用_mm_movemask_ps,以在 32 位整数的低位中获取简单的 4 位掩码。
【解决方案2】:

这个问题的答案还取决于你是否想要实际的不平等,你会使用@PaulR 所显示的内容:

bool fneq128_a (__m128 const& a, __m128 const& b)
{
    // returns true if at least one element in a is not equal to 
    // the corresponding element in b
    return _mm_movemask_ps(_mm_cmpeq_ps(a, b)) != 0xF;
}

或者您是否想使用一些 epsilon 来指定元素在不超过阈值的情况下仍被视为“相等”:

bool fneq128_b (__m128 const& a, __m128 const& b, float epsilon = 1.e-8f)
{
    // epsilon vector
    auto eps = _mm_set1_ps(epsilon);
    // absolute of difference of a and b
    auto abd = _mm_andnot_ps(_mm_set1_ps(-0.0f), _mm_sub_ps(a, b));
    // compare abd to eps
    // returns true if one of the elements in abd is not less than 
    // epsilon
    return _mm_movemask_ps(_mm_cmplt_ps(abd, eps)) != 0xF;
}

例子:

auto a = _mm_set_ps(0.0, 0.0, 0.0, 0.0);
auto b = _mm_set_ps(0.0, 0.0, 0.0, 1.e-15);
std::cout << fneq128_a(a, b) << ' ' << fneq128_b(a, b) << "\n";

打印:

 1 0

【讨论】:

    【解决方案3】:

    彼得是对的!!!在以前的方法下,针对 0.0f 值的测试可能会失败。

    请考虑这个宏。 #define ISEQUAL(A, B) _mm_testz_si128(_mm_xor_si128(_mm_castps_si128(A), _mm_castps_si128(B)),
    _mm_xor_si128(_mm_castps_si128(A), _mm_castps_si128(B)))

    这会产生 2 条指令。

    【讨论】:

    • 这不是对相等性的测试,而是在测试~a &amp; b == all-zero(跨越所有 128 位)。另见Can PTEST be used to test if two registers are both zero or some other condition?
    • 将其设为宏不方便;您不妨将其设为内联函数,这样您就可以使用临时函数来保存按位异或结果。但是,是的,如果您想测试按位相等,这应该可以工作,考虑到 NaN == NaN(具有相同的有效负载)和-0.0 != 0.0。而不是 IEEE 浮点相等规则。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-12-29
    • 1970-01-01
    • 2020-09-28
    • 1970-01-01
    相关资源
    最近更新 更多