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;

}

2 つの注意事項:

  • 目標は、同じデータに対してfftwblitz::Array演算の両方をコピーする必要なく使用できるようにすると同時にsin()、4 倍精度の複素変数のような汎用関数を使用できるようにすることです。
  • blitz-part は正常に動作しますが、これは予想どおりです。しかし、(私にとって)驚いたことは、そのfftwq_complex*部分もうまく機能することでした.
  • これは、正しい simd アライメントを保証するために使用さfftw::allocatorれる単純な置き換えですが、それはこの質問にとって重要ではないため、省略しました (少なくとも、これはこの質問にとって重要ではないと思います)。std::allocatorfftwq_malloc

私の質問は、私が踏んでいる氷はどれくらい薄いですか?

4

1 に答える 1

1

あなたはかなり節約しています:

  • std::vectorC配列と互換性があります(この質問vector.data()で回答されているように、を介して最初の要素へのポインターにアクセスできます
  • std::complex<T>T[2]は、FFTW と互換性のある form の配列と互換性があるように設計されています。これは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 を使用して) 最初の非静的データ メンバーへのポインターに変換できます。

もちろん、これは最終的に機能する場合にのみヒントを提供します。型が本当に a__float128であるかどうかはわかりませんが、 ab boost は型がその周りの薄いラッパーであると述べています。問題ないはずです。の設計または構造の変更である場合float128、静的アサーションは失敗するはずです。

于 2014-07-31T16:10:09.127 に答える