std::vector<std::complex<boost:multiprecision::float128>>(N).data() を 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;
}
2 つのコメント:
- 両方使えるようになることを目標にします
fftw
そしてblitz::Array
同じデータをコピーすることなく操作できると同時に、次のような汎用関数を使用できます。sin()
4倍精度の複素変数にも対応 - の
blitz
-part は正常に動作します。これは予想通りです。しかし、(私にとって)驚いたのは、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
. 。ブーストのドキュメントでは、これについては保証されていません。ただし、コードにいくつかの静的アサートを追加することができます。これは、変換が不可能な場合は失敗します。これは次のようになります。
static_assert(std::is_standard_layout<float128>::value,"no standard type");
static_assert(sizeof(float128) == sizeof(__float128),"size mismatch");
どこ sizeof
ブースト型と __float128 の同じサイズを保証し、 is_standard_layout 次のことを確認します。
標準レイアウト クラスへのポインタは、(reinterpret_cast を使用して) その最初の非静的データ メンバーへのポインタに変換でき、またその逆も可能です。
もちろん、これは最終的に機能する場合にのみヒントを提供するものであり、その型が本当に __float128
, 、しかし、ab boostはそのタイプがそれを囲む薄いラッパーであると述べています、それは問題ないはずです。設計や構造の変更の場合 float128
, 、静的アサーションは失敗するはずです。