std::vector<std::complex<boost:multi precision::float128>>(N).data() 可以安全地被reinterpret_casted到fftwq_complex*吗?
-
22-12-2019 - |
题
我并没有真正期望以下示例能够工作,但确实如此(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;
}
两点备注:
- 目标是能够同时使用
fftw
和blitz::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
, ,静态断言应该失败。
不隶属于 StackOverflow