PU STD :: Vector > (N) .Data () Salotto essere reinterpret_cast su FFTWQ_Complex *?
-
22-12-2019 - |
Domanda
Non mi aspettavo davvero che il seguente esempio funzioni, ma in effetti lo fa (G ++ 4.6.4, con --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;
}
.
Due osservazioni:
- .
- L'obiettivo è quello di poter utilizzare sia
fftw
e operazioni generacodicitagCodeTagCode sugli stessi dati senza la necessità di copiarli in giro contemporaneamente in grado di utilizzare Generico funzioni comeblitz::Array
anche per variabili complesse con Quad Precision La partesin()
funziona bene, che è prevista.Ma la sorpresa (a me) era che la parteblitz
funziona anche bene. - Il
fftwq_complex*
è un semplice sostituto delfftw::allocator
che utilizzeràstd::allocator
per assicurare il corretto allineamento SIMD, ma non è importante per questa domanda, quindi l'ho lasciato fuori (almeno penso che questo non sia importante per questa domanda) .
La mia domanda è: quanto è sottile il ghiaccio sto facendo un passo avanti?
Soluzione
Sei abbastanza salvo:
- .
-
std::vector
è compatibile con un array C (è possibile accedere a un puntatore al primo elemento tramitevector.data()
, come risposta in Questa domanda -
std::complex<T>
è progettato per essere compatibile con una serie di formeT[2]
, che è compatibile con FFTW. Questo è descritto in Documentazione FFTW.
C ++ ha la propria classe di modello complessa, definita nel file di intestazione standard. Secondo quanto riferito, il comitato degli standard C ++ ha recentemente accettato di accendere che il formato di archiviazione utilizzato per questo tipo sia compatibile con il tipo binario con il tipo C99, I.e. Un array T [2] con parti reali [0 0] e immaginarie consecutive. (Vedi rapporto http://www.open -std.org/JTC1/SC22/WG21/Docs/Papers/2002/N1388.pdf WG21 / N1388.) Anche se non parte dello standard ufficiale come di questa scrittura, la proposta ha dichiarato che: "Questa soluzione ha stato testato con tutte le attuali implementazioni principali della biblioteca standard e ha dimostrato di lavorare. " Nella misura in cui questo è vero, se hai un complesso variabile * X, è possibile passarlo direttamente a FFTW tramite reinterpret_cast (X).
L'unica cosa da tenere a mente è che il data()
viene invalidato se si aggiungono valori al tuo vettore.
Per l'ultima parte c'è la compatibilità tra
boost::multiprecision::float128
e __float128
. La documentazione boost non fornisce alcuna garanzia a riguardo.
Ciò che può essere fatto tuttavia, è aggiungere alcune asserzioni statiche nel codice, che non riescono se la conversione non è possibile. Questo potrebbe sembrare questo:
static_assert(std::is_standard_layout<float128>::value,"no standard type");
static_assert(sizeof(float128) == sizeof(__float128),"size mismatch");
.
dove sizeof
garantisce la stessa dimensione del tipo di boost e __Float128 e IS_STANDARD_Layout controlla che:
.Un puntatore a una classe di layout standard può essere convertito (con reinterpret_cast) a un puntatore al primo membro dei dati non statici e viceversa.
Certo, questo dà suggerimenti solo se funziona alla fine, come non puoi dire se il tipo è davvero un __float128
, ma AB Boost afferma che il loro tipo è un involucro sottile attorno ad esso, dovrebbe andare bene. Se i loro sono cambiamenti in progettazione o struttura di float128
, le asserzioni statiche dovrebbero fallire.