哪个是avx浮点按位逻辑运算的原因?

时间:2014-07-24 20:38:35

标签: c++ simd avx avx2

AVX允许按位逻辑运算,例如和/或浮点数据类型__m256和__m256d。

但是,C ++并不允许对浮点数和双精度数进行逐位运算。如果我是对的,浮点数的内部表示无法保证,编译器是否会使用IEEE754,因此程序员无法确定浮点数的位置如何等。

考虑这个例子:

#include <immintrin.h>
#include <iostream>
#include <limits>
#include <cassert>

int main() {

    float x[8] = {1,2,3,4,5,6,7,8};
    float mask[8] = {-1,0,0,-1,0,-1,0,0};
    float x_masked[8];

    assert(std::numeric_limits<float>::is_iec559);

    __m256 x_ = _mm256_load_ps(x);
    __m256 mask_ = _mm256_load_ps(mask);

    __m256 x_masked_ = _mm256_and_ps(x_,mask_);

    _mm256_store_ps(x_masked,x_masked_);

    for(int i = 0; i < 8; i++)
        std::cout << x_masked[i] << " ";

    return 0;
}

假设使用了IEEE754,因为-1的表示是0xffffffff,我希望输出为

1,0,0,4,0,6,0,0

而不是

1 0 0 1.17549e-38 0 1.17549e-38 0 0

因此,我对内部表征的假设可能是错误的(或者我犯了一些愚蠢的错误)。

所以问题是:有没有一种方法可以使用浮点逻辑并确保结果有意义?

3 个答案:

答案 0 :(得分:8)

如果你正在使用AVX内在函数,那么你就知道你正在使用IEEE754浮点数,因为那是AVX所做的。

对浮点数的一些有意义的操作是有意义的

  • 选择,如Jens&#39;回答,虽然从SSE4.1开始我们有blendvps及其亲戚在一条指令中做到这一点
  • 绝对值(掩盖标志)
  • 否定(xor with -0.0f)
  • 转移标志
  • 提取指数(罕见)

主要用于操纵符号,或者选择性地清除整个浮点数,而不是用指数或有效数字的各个位置进行捣乱 - 你可以做到,但它很少有用

答案 1 :(得分:4)

原因是在执行单位的域之间切换可能会受到惩罚bypass-delays-when-switching-execution-unit-domainswhy-do-some-sse-mov-instructions-specify-that-they-move-floating-point-values。在这种情况下,从浮点AVX执行单元切换到整数执行AVX单元。

例如,假设您要比较浮点AVX寄存器xy

z = _mm256_cmp_ps(x, y, 1);

AVX寄存器z包含布尔整数值(0或-1),如果需要,您可以使用_mm256_and_ps_mm256_and_si256进行逻辑AND。但是_mm256_and_ps停留在同一个执行单元中,而_mm256_and_si256会切换可能导致旁路延迟的单位。

编辑:关于C ++中浮点数的按位运算符,它当然是可能的,有时也很有用。这是一些简单的例子。

union {
    float f;
    int i;
} u;
u.i ^= 0x80000000; // flip sign bit of u.f
u.i &= 0x7FFFFFFF; // set sign bit to zero //take absolute value

答案 2 :(得分:2)

程序员可以完全确定如何表示单精度浮点。如何实现功能是另一个故事。我已经使用按位运算来实现符合IEEE-754的半精度浮点数。我还在2003年之前利用了拆分分支的操作​​ - 在IBM为此提出专利之前。

static inline __m128 _mm_sel_ps(__m128 a, __m128 b, __m128 mask ) {
    b = _mm_and_ps( b, mask );
    a = _mm_andnot_ps( mask, a );
    return _mm_or_ps( a, b );
}

此示例演示如何使用SSE2删除浮点分支。使用AVX也可以实现同样的目的。如果您尝试(使用相同的技术)使用标量删除分支,则由于上下文的切换而无法获得任何性能(适用于x86 - 不适用于具有fpsel操作的ARM)