Wie berechnet diese Funktion den absoluten Wert eines Gleitkommas durch eine NOT- und eine AND-Operation?

Ich versuche zu verstehen, wie der folgende Codeausschnitt funktioniert. Dieses Programm verwendet SIMD-Vektoranweisungen (Intel SSE), um den Absolutwert von 4 Floats zu berechnen (also im Grunde eine vektorisierte "fabs ()" - Funktion).

Hier ist der Ausschnitt:

#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;
}

Jetzt weiß ich, dass es funktioniert, da ich das Programm selbst ausgeführt habe, um es zu testen. Wenn es mit g ++ 4.8.2 kompiliert wird, ist das Ergebnis:

x[0]: 4
x[1]: 20
x[2]: 15
x[3]: 143

Drei (verwandte) Fragen rätseln mich:

Wie ist es überhaupt möglich, eine bitweise Funktion auf einen Float anzuwenden? Wenn ich dies in Vanilla C ++ versuche, wird mir mitgeteilt, dass dies nur für ganzzahlige Typen funktioniert (was sinnvoll ist).

Aber zweitens und noch wichtiger: Wie funktioniert es überhaupt? Wie hilft Ihnen ein NOT und ein AND? Wenn Sie dies in Python mit einem ganzzahligen Typ versuchen, erhalten Sie nur das erwartete Ergebnis: Jede ganzzahlige Zahl AND -1 (die NICHT 0 ist) gibt Ihnen einfach diese Zahl zurück, ändert aber das Vorzeichen nicht. Wie funktioniert das hier?

Drittens ist mir aufgefallen, dass das Programm den absoluten Wert nicht mehr angibt, wenn ich den Wert des für die NAND-Operation verwendeten Gleitkommas (markiert mit drei ???) von -0,0 auf 0,0 ändere. Aber wie kann es überhaupt ein -0.0 geben und wie hilft es?

Hilfreiche Referenzen:

Intel Intrinsics Guide