Puede std::vector<std::complex<boost:multiprecision::float128>>(N).los datos de() de forma segura reinterpret_casted a fftwq_complex*?

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

Pregunta

Realmente no me esperaba el siguiente ejemplo para el trabajo, pero de hecho lo hace (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;

}

Dos observaciones:

  • El objetivo es ser capaz de utilizar tanto fftw y blitz::Array las operaciones en los mismos datos, sin la necesidad de copiar alrededor de ellos, mientras que al mismo tiempo ser capaz de utilizar el término genérico funcionst como sin() también para variables complejas con precisión quad
  • El blitz-parte funciona bien, lo que se espera.Pero la sorpresa (para mí) era, que el fftwq_complex* parte también funciona bien.
  • El fftw::allocator es una simple sustitución de la std::allocator que va a utilizar fftwq_malloc para garantizar el correcto simd alineación, pero que no es importante para esta pregunta, así que me dejaron (al menos creo que esto no es importante para esta pregunta)

Mi Pregunta es:Lo delgado que es el hielo estoy pisando?

¿Fue útil?

Solución

Usted está bastante guardar:

  • std::vector es compatible con una matriz C (usted puede tener acceso a un puntero al primer elemento a través de la vector.data(), como respondió en esta pregunta
  • std::complex<T> está diseñado para ser compatible con una Matriz de la forma T[2], que es compatible con FFTW.Esto se describe en el FFTW documentación

    C++ tiene su propio complejo de clase de plantilla, que se define en el archivo de encabezado estándar.Según los informes, el comité de estándares de C++ ha acordado recientemente un mandato para que el formato de almacenamiento utilizado para este tipo de ser compatibles con el binario con el C99 tipo, es decir,una matriz T[2] con el consecutivo el real [0] y de lo imaginario [1] partes.(Véase el informe http://www.open-std.org/jtc1/sc22/WG21/docs/papers/2002/n1388.pdf WG21/N1388.) Aunque no forma parte oficial de la norma a partir de este escrito, la propuesta establece que:"Esta solución ha sido probado con todas las implementaciones principales de la biblioteca estándar y de la muestra a trabajar." En la medida en que esto es cierto, si tenemos una variable compleja *x, puede pasar directamente a FFTW a través de reinterpret_cast(x).

La única cosa a tener en cuenta es que la data() consigue invalidado si usted agregar valores para el vector.


Para la última parte es la compatibilidad entre boost::multiprecision::float128 y __float128.El impulso de la documentación no ofrece ninguna garantía acerca de esto.¿Qué se puede hacer sin embargo, es añadir algo de estática afirma en su código, que no se si la conversión no es posible.Esto podría tener este aspecto:

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

Donde sizeof garantiza el mismo tamaño de la boost tipo y __float128, y is_standard_layout comprueba que:

Un puntero a una clase de diseño puede convertirse (con reinterpret_cast) a un puntero a su primer no-miembro de datos estáticos y viceversa.

Por supuesto, esto sólo da pistas si funciona en la final, ya que no podemos decir si el tipo es realmente un __float128, pero ab impulsar a los estados de su tipo es una envoltura alrededor de ella, que debería estar bien.Si hay cambios en el diseño o estructura de float128, la estática afirmaciones debería fallar.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top