سؤال

أنا استخدم cpp_dec_float للحصول على دقة عشوائية، وهو أمر رائع، لكني أواجه مشكلة في معرفة كيفية طباعة جميع الأرقام المهمة.

على سبيل المثال، مع هذا الرمز للإعداد

using boost::multiprecision::cpp_dec_float;
typedef boost::multiprecision::number<cpp_dec_float<100>> mp_type;

mp_type test_num("7.0710678118654752440084436210484903928483593768847403658833986900e-01");

وإذا قمت بالطباعة باستخدام

std::cout << std::scientific << test_num << std::endl;

النتيجه هي 7.071068e-01, ، لذلك انتهى الأمر.

إذا ذهبت للانفصال

std::cout << std::setprecision(std::numeric_limits<mp_type>::digits) << std::scientific << test_num << std::endl;

انا حصلت 7.0710678118654752440084436210484903928483593768847403658833986900000000000000000000000000000000000000e-01.يسعدني ألا أفقد الدقة، لكنها ليست محافظة جدًا على المساحة.

هل هناك طريقة لإزالة الأصفار الزائدة دون فقدان أي دقة باستخدام الأدوات الموجودة؟إذا لم يكن الأمر كذلك، فكيف يمكن إزالة الأصفار الزائدة من السلسلة الناتجة؟

إذا كان من الممكن استخدام الأدوات الموجودة لتحقيق هدفي، فكيف يمكن ذلك؟ cpp_dec_float هل يتم إخراجها بالتدوين العلمي دون فقدان الدقة وإزالة الأصفار الزائدة إلى سلسلة؟لا أستطيع إلا أن أجد أمثلة الدفق.

أقرب

بفضل واجهة وهمية، أنا أقرب بكثير.

لقد قمت بتغيير الكود إلى هذا:

using boost::multiprecision::cpp_dec_float;
typedef boost::multiprecision::number<cpp_dec_float<0>> mp_type;
mp_type test_num("7.0710678118654752440084436210484903928483593768847403658833986900e-01");
std::cout << test_num.str(0, std::ios_base::scientific) << std::endl;

أن يكون لديك طول غير محدود؛ومع ذلك، تتم طباعة هذا:

7.0710678118654752440084436210484903928480e-01

وهو قريب ولكن يبدو غريبا.في ال مصدر واجهة وهمية أشار لي بلطف، وجدت هذه السطور

if(number_of_digits == 0)
    number_of_digits = cpp_dec_float_total_digits10;

مما يوحي لي أنه يجب أن يأخذ في الاعتبار جميع الأرقام المهمة، وإخراج ما تم إدخاله بشكل أساسي بسبب الطول غير المحدود.

لقد راجعت مصدر ل cpp_dec_float_total_digits10, ، وأنا غير قادر على تحديد ما هو بالضبط؛على الرغم من أنني وجدت قسم الكود هذا الذي يبدو أنه يحدده.

private:
   static const boost::int32_t cpp_dec_float_elem_digits10 = 8L;
   static const boost::int32_t cpp_dec_float_elem_mask     = 100000000L;

   BOOST_STATIC_ASSERT(0 == cpp_dec_float_max_exp10 % cpp_dec_float_elem_digits10);

   // There are three guard limbs.
   // 1) The first limb has 'play' from 1...8 decimal digits.
   // 2) The last limb also has 'play' from 1...8 decimal digits.
   // 3) One limb can get lost when justifying after multiply,
   //    as only half of the triangle is multiplied and a carry
   //    from below is missing.
   static const boost::int32_t cpp_dec_float_elem_number_request = static_cast<boost::int32_t>((cpp_dec_float_digits10 / cpp_dec_float_elem_digits10) + (((cpp_dec_float_digits10 % cpp_dec_float_elem_digits10) != 0) ? 1 : 0));

   // The number of elements needed (with a minimum of two) plus three added guard limbs.
   static const boost::int32_t cpp_dec_float_elem_number = static_cast<boost::int32_t>(((cpp_dec_float_elem_number_request < 2L) ? 2L : cpp_dec_float_elem_number_request) + 3L);

public:
   static const boost::int32_t cpp_dec_float_total_digits10 = static_cast<boost::int32_t>(cpp_dec_float_elem_number * cpp_dec_float_elem_digits10);

هل يمكن تحديد عدد الأرقام المهمة واستخدامها كوسيطة أولى لـ boost::multiprecision::cpp_dec_float::str()?

هل كانت مفيدة؟

المحلول

تبين أن هذا أمر صعب.

القصة القصيرة هي:لا توجد مثل هذه الوظيفة في cpp_dec_float.والأسوأ من ذلك أن cpp_dec_float لا يتتبع عدد الأرقام المهمة التي تم تعيينها، لذلك لا توجد طريقة "رخيصة" للعثور على الطول المطلوب لطباعة الكسر.

الأفكار:

  • بالنسبة لبعض الحالات الحدودية (على سبيل المثال.123.000000000000001) يمكن للمرء أن يأخذ log10 من مقلوب الجزء الكسري + log10 من الجزء الصحيح.هذا لا يمكن تطبيقه بشكل عام.

  • إذا كنت تريد استخدام تفاصيل التنفيذ، فقد تجد العنصر "آخر مأهول" في مصفوفة الواجهة الخلفية، وتقوم بإجراء العمليات الحسابية.ومع ذلك، هذا أمر متضمن إلى حد كبير (يتطلب التعديل cpp_dec_float.hpp والاختبارات كثيرة).

  • وأخيرا، لاحظت أن التنفيذ الحالي ل .str() يجعل بوضوح صفر جهد ليكون فعالا.على الاطلاق.

لذلك بشكل عام لدي الاقتراحات التالية.أيضاً

  1. التبديل إلى gmp الخلفية (إذا كنت تستطيع ذلك).ملحوظة

    • هذا ليس تمثيلًا عشريًا لـ AFAICT
    • وهذا يتطلب ربط مكتبة إضافية (libgmp).
    • gmp_float يفعل لديها دقة تعسفية بالرغم من ذلك، و
    • إنه str() تطبيق يفعل تأخذ في الاعتبار أهمية الأصفار في الجزء العشري

    شاهده العيش على كوليرو

    #include <boost/multiprecision/number.hpp>
    #include <boost/multiprecision/gmp.hpp>
    #include <iostream>
    
    namespace mp = boost::multiprecision;
    
    int main()
    {
        typedef mp::number<mp::gmp_float<100>> mp_type;
        mp_type test_num("7.071067811865475244008443621048490392848359376884740365883398690000000000000000000e-01");
    
        std::cout << test_num.str(0, std::ios_base::scientific) << '\n';
    }
    

    مطبوعات 7.071067811865475244008443621048490392848359376884740365883398690e-01 دون الحاجة إلى اتخاذ مزيد من الإجراءات.

  2. إذا لم يكن هذا خيارًا، فسأقوم فقط بمعالجة الإخراج لاحقًا، وإزالة الأصفار الزائدة:

    template <typename T>
    std::string to_pretty_string(T const& v)
    {
        std::string s = v.str(0, std::ios_base::scientific);
        assert(s.length()>3); // min: 0.e
        switch (s[0])
        { // normalized scientific always has #.####### form of mantissa
            case '-':
            case '+': assert(s[2] == '.'); break;
            default:  assert(s[1] == '.'); break;
        }
    
        auto exp = s.find('e');
        if (std::string::npos != exp && exp > 0)
        {
            for(size_t pos = exp-1; pos; --pos)
            {
                if (s[pos] != '0')
                {
                    // remove run of 0s if applicable
                    s.erase(pos+1, exp-pos-1); 
                    break;
                }
            }
        }
        return std::move(s);
    }
    

شاهده العيش على كوليرو مرة أخرى

نصائح أخرى

يمكنك ذكر صريح عدد الأرقام التي تحتاجها لتكون إخراجها باستخدام طريقة GransoSodicetagCode:

giveacodicetagpre.

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