c++boostfftwmultiprecision

Can std::vector<std::complex<boost:multiprecision::float128>>(N).data() safely be reinterpret_casted to fftwq_complex*?


I did not really expect the following example to work, but indeed it does (g++ 4.6.4, with --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;

}

Two remarks:

My Question is: How thin is the ice I'm stepping on?


Solution

  • You're pretty much save:

    The only thing to keep in mind is that the data() gets invalidated if you add values to your vector.


    For the last part there is the compatiblity between boost::multiprecision::float128 and __float128. The boost documentation gives no guarantee about this. What can be done however, is to add some static asserts in your code, which fails if the conversion is not possible. This could look like this:

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

    Where sizeof guarantees the same size of the boost type and __float128, and is_standard_layout checks that:

    A pointer to a standard-layout class may be converted (with reinterpret_cast) to a pointer to its first non-static data member and vice versa.

    Of course, this only gives hints if it works in the end, as you cannot say if the type is really a __float128, but ab boost states their type is a thin wrapper around it, it should be fine. If their are changes in design or structure of float128, the static assertions should fail.