0

我真的没想到下面的例子可以工作,但确实可以(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()也可用于具有四精度的复杂变量
  • -partblitz工作正常,这是预期的。但(对我来说)令我惊讶的是,这fftwq_complex*部分也能正常工作。
  • fftw::allocator是一个简单的替代品,std::allocator用于fftwq_malloc确保正确的 simd 对齐,但这对这个问题并不重要,所以我把它省略了(至少我认为这对这个问题并不重要)

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

4

1 回答 1

1

您几乎可以节省:

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

    C++ 有自己的复杂模板类,在标准头文件中定义。据报道,C++ 标准委员会最近同意强制用于这种类型的存储格式与 C99 类型二进制兼容,即具有连续实部 [0] 和虚部 [1] 部分的数组 T[2]。(请参阅报告http://www.open-std.org/jtc1/sc22/WG21/docs/papers/2002/n1388.pdf WG21/N1388。)虽然在撰写本文时不是官方标准的一部分,但该提案指出那:“这个解决方案已经过标准库的所有当前主要实现的测试,并且证明是有效的。” 如果这是真的,如果你有一个变量 complex *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");

wheresizeof保证 boost 类型和 __float128 的大小相同,并且is_standard_layout检查:

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

当然,这仅在它最终起作用时才给出提示,因为您不能说类型是否真的是 a __float128,但是 ab boost 指出它们的类型是围绕它的薄包装,应该没问题。如果它们的设计或结构发生变化float128,则静态断言应该失败。

于 2014-07-31T16:10:09.127 回答