std::vector<std::complex<boost:multi precision::float128>>(N).data() 可以安全地被reinterpret_casted到fftwq_complex*吗?

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

我并没有真正期望以下示例能够工作,但确实如此(g++ 4.6.4,带有 --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;

}

两点备注:

  • 目标是能够同时使用 fftwblitz::Array 对相同数据进行操作,无需复制它们,同时能够使用通用函数,例如 sin() 也适用于具有四精度的复杂变量
  • blitz- 部分工作正常,这是预期的。但令我惊讶的是, fftwq_complex* 部分也工作正常。
  • fftw::allocator 是一个简单的替代 std::allocator 这将使用 fftwq_malloc 确保正确的 simd 对齐,但这对于这个问题并不重要,所以我忽略了它(至少我认为这对于这个问题并不重要)

我的问题是:我踩的冰有多薄?

有帮助吗?

解决方案

你几乎节省了:

  • std::vector 与 C 数组兼容(您可以通过以下方式访问指向第一个元素的指针 vector.data(), ,如中所回答 这个问题
  • std::complex<T> 被设计为与数组形式兼容 T[2], ,与 FFTW 兼容。这在 FFTW 文档

    C++ 有自己的复杂模板类,在标准头文件中定义。据报道,C++标准委员会最近同意强制该类型使用的存储格式与C99类型二进制兼容,即具有连续实部 [0] 和虚部 [1] 部分的数组 T[2]。(见报告 http://www.open-std.org/jtc1/sc22/WG21/docs/papers/2002/n1388.pdf WG21/N1388。)虽然在撰写本文时尚未成为官方标准的一部分,但该提案指出:“该解决方案已通过标准库的所有当前主要实现进行了测试,并证明是有效的。”在这是真的的范围内,如果您具有可变复杂 *X,则可以通过reinterpret_cast(x)将其直接传递给FFTW。

唯一要记住的是 data() 如果您向向量添加值,则会失效。


对于最后一部分,两者之间存在兼容性 boost::multiprecision::float128__float128. 。boost 文档对此不提供任何保证。但是,可以做的是在代码中添加一些静态断言,如果无法进行转换,则会失败。这可能看起来像这样:

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

在哪里 sizeof 保证 boost 类型和 __float128 的大小相同,并且 is_standard_layout 检查:

指向标准布局类的指针可以转换(使用reinterpret_cast)到指向其第一个非静态数据成员的指针,反之亦然。

当然,这只是给出了最终是否有效的提示,因为你不能说该类型是否真的是一个 __float128, ,但是 ab boost 声明他们的类型是围绕它的薄包装,应该没问题。如果它们的设计或结构发生变化 float128, ,静态断言应该失败。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top