Как эта функция вычисляет абсолютное значение с плавающей запятой через операции NOT и AND?

Я пытаюсь понять, как работает следующий фрагмент кода. Эта программа использует векторные инструкции 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 и как он помогает?

Полезные ссылки:

Руководство по встроенным функциям Intel

4

Решение

-0.0 представляется как 1000...0001. Следовательно _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.

5

Другие решения