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;
}
Run Code Online (Sandbox Code Playgroud)
假设使用IEEE754,因为-1的表示是0xffffffff,我希望输出为
1,0,0,4,0,6,0,0
Run Code Online (Sandbox Code Playgroud)
而它反而是
1 0 0 1.17549e-38 0 1.17549e-38 0 0
Run Code Online (Sandbox Code Playgroud)
因此,我对内部表征的假设可能是错误的(或者我犯了一些愚蠢的错误).
所以问题是:有没有一种方法可以使用浮点逻辑并且对结果有意义的事实保持安全?
如果你正在使用AVX内在函数,那么你知道你正在使用IEEE754浮点数,因为这就是AVX所做的.
浮点数的一些有意义的操作是有意义的
blendvps及其亲属在一条指令中做到这一点主要是操纵符号,或选择性地清除整个浮点数,而不是用指数或有效数字的各个位进行捣乱 - 你可以做到,但它很少有用.
原因是执行单元域之间的切换可能会受到惩罚,bypass-delays-when-switching-execution-unit-domains 和why-do-some-sse-mov-instructions-specify-that-the-move-floating点值。在这种情况下,从浮点 AVX 执行单元切换到整数执行 AVX 单元。
例如,假设您想与浮点 AVX 寄存器进行比较,x并且y
z = _mm256_cmp_ps(x, y, 1);
Run Code Online (Sandbox Code Playgroud)
AVX 寄存器z包含布尔整数值(0 或 -1),然后您可以根据需要对这些值进行逻辑 AND 使用_mm256_and_ps或 with _mm256_and_si256。但是_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
Run Code Online (Sandbox Code Playgroud)