Я пытаюсь понять, как работает следующий фрагмент кода. Эта программа использует векторные инструкции SIMD (Intel SSE) для вычисления абсолютного значения 4-х чисел (так что, в основном, векторизованная функция «fabs ()»).
Вот фрагмент:
#include <iostream>
#include "xmmintrin.h"
template <typename T>
struct alignas(16) sse_t
{
T data[16/sizeof(T)];
};
int main()
{
sse_t<float> x;
x.data[0] = -4.;
x.data[1] = -20.;
x.data[2] = 15.;
x.data[3] = -143.;
__m128 a = _mm_set_ps1(-0.0); // ???
__m128 xv = _mm_load_ps(x.data);
xv = _mm_andnot_ps(a,xv); // <-- Computes absolute value
sse_t<float> result;
_mm_store_ps(result.data, xv);
std::cout << "x[0]: " << result.data[0] << std::endl;
std::cout << "x[1]: " << result.data[1] << std::endl;
std::cout << "x[2]: " << result.data[2] << std::endl;
std::cout << "x[3]: " << result.data[3] << std::endl;
}
Теперь я знаю, что это работает, так как я сам запустил программу, чтобы протестировать ее. Когда скомпилировано с g ++ 4.8.2, результат:
x[0]: 4
x[1]: 20
x[2]: 15
x[3]: 143
Три (связанные) вопросы озадачивают меня:
Во-первых, как вообще можно взять побитовую функцию и применить ее к плавающей запятой? Если я попробую это в vanilla C ++, это сообщит мне, что это работает только для целочисленных типов (что имеет смысл).
Но, во-вторых, и что более важно:
Как это вообще работает? Как принимать НЕ, И И даже помочь вам здесь? Попытка сделать это в Python с целочисленным типом просто дает ожидаемый результат: любое целое число AND -1 (которое НЕ равно 0) просто возвращает вам это число, но не меняет знак. Так как это работает здесь?
В-третьих, я заметил, что если я изменю значение с плавающей запятой, используемое для операции NAND (помечено тремя ???), с -0,0 до 0,0, программа больше не даст мне абсолютное значение. Но как вообще может существовать -0.0 и как он помогает?
Полезные ссылки:
-0.0
представляется как 1000...000
1. Следовательно _mm_andnot_ps(-0.0, x)
2 эквивалентно 0111...111 & x
, Это заставляет MSB (который является знаковым битом) равным 0.
1. В IEEE-754, по крайней мере.
2. The _mm_andnot_ps
внутренняя не означает «NAND»; см. например http://msdn.microsoft.com/en-us/library/68h7wd02(v=vs.90).aspx.