هل يمكن إعادة تفسير std::vector<std::complex<boost:multiprecision::float128>>(N).data() بأمان إلى 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;

}

ملاحظتان:

  • الهدف هو أن تكون قادرًا على استخدام كليهما 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، أي.مصفوفة T[2] تحتوي على أجزاء حقيقية [0] وخيالية [1] متتالية.(انظر التقرير http://www.open-std.org/jtc1/sc22/WG21/docs/papers/2002/n1388.pdf WG21/N1388.) على الرغم من أنه ليس جزءًا من المعيار الرسمي حتى كتابة هذه السطور، إلا أن الاقتراح ينص على ما يلي:"تم اختبار هذا الحل مع جميع التطبيقات الرئيسية الحالية للمكتبة القياسية وأظهر أنها تعمل." إلى الحد الذي يكون هذا صحيحًا ، إذا كان لديك مجمع متغير *x ، فيمكنك تمريره مباشرة إلى FFTW عبر reinterpret_cast (x).

الشيء الوحيد الذي يجب أخذه في الاعتبار هو أن 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, ، يجب أن تفشل التأكيدات الثابتة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top