Peut std::vector<std::complex<boost:multiprecision::float128>>(N).les données de() en toute sécurité être reinterpret_casted à fftwq_complex*?

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

Question

Je n'ai pas vraiment s'attendre à l'exemple suivant pour le travail, mais en effet il n' (g++ 4.6.4, avec-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;

}

Deux remarques:

  • L'objectif est d'être en mesure d'utiliser les deux fftw et blitz::Array opérations sur les mêmes données, sans avoir besoin de les copier autour tandis que dans le même temps être en mesure d'utiliser générique funcionst comme sin() aussi pour les variables complexes avec précision quad
  • L' blitz-partie fonctionne bien, ce qui est prévu.Mais la surprise (pour moi) est que la fftwq_complex* partie fonctionne aussi très bien.
  • L' fftw::allocator est un simple remplacement de std::allocator qui va l'utiliser fftwq_malloc pour assurer la correcte simd alignement, mais ce n'est pas important pour cette question, alors je l'ai laissé (au moins je pense que ce n'est pas important pour cette question)

Ma Question est:Comment mince, c'est la glace que je suis marcher sur?

Était-ce utile?

La solution

Vous êtes assez bien enregistrer:

  • std::vector est compatible avec un C array (vous pouvez accéder à un pointeur vers le premier élément via vector.data(), comme répondu dans cette question
  • std::complex<T> est conçu pour être compatible avec une Matrice de la forme T[2], qui est compatible avec FFTW.Ceci est décrit dans le FFTW documentation

    C++ a son propre complexe de classe de modèle, défini dans la norme en-tête de fichier.Apparemment, le C++ comité de normalisation a récemment décidé de mandat que le format de stockage utilisé pour ce type d'être compatible au niveau binaire avec le C99 type, c'est à direun tableau T[2] avec consécutives réel [0] et imaginaire [1] les pièces.(Voir le rapport http://www.open-std.org/jtc1/sc22/WG21/docs/papers/2002/n1388.pdf WG21/N1388.) Bien que ne faisant pas partie de la norme officielle de cette écriture, la proposition a déclaré que:“Cette solution a été testée avec toutes les grandes implémentations de la bibliothèque standard et visible.” Dans la mesure où cela est vrai, si vous disposez d'une variable complexe *x, vous pouvez passer directement à FFTW via reinterpret_cast(x).

La seule chose à garder à l'esprit est que l' data() soient invalidées si vous ajoutez de la valeur à vos vecteur.


Pour la dernière partie il y a la compatibilité entre boost::multiprecision::float128 et __float128.Le coup de pouce de la documentation ne donne aucune garantie à ce sujet.Ce qui peut être fait, cependant, est d'ajouter quelques statique affirme, dans votre code, ce qui échoue si la conversion n'est pas possible.Cela pourrait ressembler à ceci:

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

sizeof les garanties de la même taille que le coup de pouce type et __ _ _ float128, et is_standard_layout vérifie que:

Un pointeur vers un standard-classe de mise en page peut être convertie (avec reinterpret_cast) à un pointeur vers son premier non-membre de données statiques et vice versa.

Bien sûr, cela ne donne que des conseils si il fonctionne en fin de compte, que vous ne pouvez pas dire si le type est vraiment un __float128, mais ab stimuler les membres de leur type est un wrapper mince autour d'elle, elle doit être fine.Si leurs sont les changements dans la conception ou la structure de float128, la statique des assertions doivent échouer.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top