Kann std::vector<std::complex<boost:multiprecision::float128>>(N).data() sicher in fftwq_complex* neu interpretiert werden?

StackOverflow https://stackoverflow.com//questions/25061663

Frage

Ich habe nicht wirklich erwartet, dass das folgende Beispiel funktioniert, aber tatsächlich funktioniert es (g++ 4.6.4, mit --std=c++0x):

#include <boost/multiprecision/float128.hpp> 
#include <blitz/array.h>
#include <fftw3.h>


int main(int /*argc*/, char** /*argv*/)
{
    //these are the same
    std::cout << sizeof(std::complex<boost::multiprecision::float128>) << " " << sizeof(fftwq_complex) << std::endl;


    typedef std::vector< std::complex<boost::multiprecision::float128> >   boost128cvec;
    //typedef std::vector<std::complex<boost::multiprecision::float128> , fftw::allocator< std::complex<boost::multiprecision::float128> > >   boost128cvec;

    //declare a std::vector consisting of std::complex<boost::multiprecision::float128>
    boost128cvec test_vector3(12);

    //casting its data storatge to fftwq_complex*
    fftwq_complex* test_ptr3 = reinterpret_cast<fftwq_complex*>(test_vector3.data());

    //also create a view to the same data as a blitz::Array
    blitz::Array<std::complex<boost::multiprecision::float128>, 1> test_array3(test_vector3.data(), blitz::TinyVector<int, 1>(12), blitz::neverDeleteData);

    test_vector3[3] = std::complex<boost::multiprecision::float128>(1.23,4.56);

    //this line would not work with std::vector
    test_array3 = sin(test_array3);

    //this line would not work with the built-in type __float128
    test_vector3[4] = sin(test_vector3[3]);

    //all of those print the same numbers
    std::cout << "fftw::vector: " << test_vector3[3].real()       << " + i " << test_vector3[3].imag() << std::endl;
    std::cout << "fftw_complex: " << (long double)test_ptr3[3][0] << " + i " << (long double)test_ptr3[3][1] << std::endl;
    std::cout << "blitz:        " << test_array3(3).real()        << " + i " << test_array3(3).imag() << std::endl << std::endl;

}

Zwei Anmerkungen:

  • Ziel ist es, beides nutzen zu können fftw Und blitz::Array Operationen an denselben Daten, ohne dass diese kopiert werden müssen, und gleichzeitig die Möglichkeit, generische Funktionen wie z. B. zu verwenden sin() auch für komplexe Variablen mit vierfacher Genauigkeit
  • Der blitz-Teil funktioniert einwandfrei, was erwartet wird.Aber die Überraschung (für mich) war, dass das fftwq_complex* Teil funktioniert auch gut.
  • Der fftw::allocator ist ein einfacher Ersatz für std::allocator was verwendet wird fftwq_malloc um eine korrekte SIMD-Ausrichtung sicherzustellen, aber das ist für diese Frage nicht wichtig, also habe ich es weggelassen (zumindest denke ich, dass das für diese Frage nicht wichtig ist)

Meine Frage ist:Wie dünn ist das Eis, auf das ich trete?

War es hilfreich?

Lösung

Du bist ziemlich sicher:

  • std::vector ist mit einem C-Array kompatibel (Sie können über auf einen Zeiger auf das erste Element zugreifen vector.data(), wie in beantwortet diese Frage
  • std::complex<T> ist so konzipiert, dass es mit einem Array von Formularen kompatibel ist T[2], das mit FFTW kompatibel ist.Dies ist im beschrieben FFTW-Dokumentation

    C++ verfügt über eine eigene komplexe Vorlagenklasse, die in der Standard-Header-Datei definiert ist.Berichten zufolge hat sich das C++-Standardkomitee kürzlich darauf geeinigt, vorzuschreiben, dass das für diesen Typ verwendete Speicherformat binärkompatibel mit dem C99-Typ sein muss, d. h.ein Array T[2] mit aufeinanderfolgenden Realteilen [0] und Imaginärteilen [1].(Siehe Bericht http://www.open-std.org/jtc1/sc22/WG21/docs/papers/2002/n1388.pdf WG21/N1388.) Obwohl es zum jetzigen Zeitpunkt nicht Teil des offiziellen Standards war, hieß es im Vorschlag:"Diese Lösung wurde mit allen aktuellen wichtigen Implementierungen der Standardbibliothek getestet und funktioniert als funktioniert." In dem Maße, in dem dies zutreffend ist, können Sie sie direkt über reinterpret_cast (x) an FFTW übergeben.

Das Einzige, was Sie beachten sollten, ist, dass die data() wird ungültig, wenn Sie Ihrem Vektor Werte hinzufügen.


Für den letzten Teil gibt es die Kompatibilität zwischen boost::multiprecision::float128 Und __float128.Die Boost-Dokumentation gibt hierfür keine Garantie.Sie können jedoch einige statische Zusicherungen in Ihren Code einfügen, was jedoch fehlschlägt, wenn die Konvertierung nicht möglich ist.Das könnte so aussehen:

static_assert(std::is_standard_layout<float128>::value,"no standard type");
static_assert(sizeof(float128) == sizeof(__float128),"size mismatch");

Wo sizeof garantiert die gleiche Größe des Boost-Typs und __float128, und is_standard_layout prüft Folgendes:

Ein Zeiger auf eine Standard-Layout-Klasse kann (mit reinterpret_cast) in einen Zeiger auf ihr erstes nicht statisches Datenelement konvertiert werden und umgekehrt.

Dies gibt natürlich nur Hinweise darauf, ob es am Ende funktioniert, da man nicht sagen kann, ob es sich bei dem Typ wirklich um einen handelt __float128, aber ab boost gibt an, dass ihr Typ eine dünne Hülle um ihn herum ist, es sollte in Ordnung sein.Wenn es Änderungen im Design oder in der Struktur gibt float128, sollten die statischen Behauptungen fehlschlagen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top