我在使用 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 将产出在科学符号没有失精确度和尾随零删除一个字符串?我只能找到 流的例子.

由于mockinterface,我非常接近。

我已经改变了的代码这样的:

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

这是接近,但似乎很奇怪。在 来源 mockinterface如此慷慨地向我指出,我发现这些路线

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() 执行情况 考虑的重要意义的零在尾数

    看到它 生活在Coliru

    #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);
    }
    

看到它 生活在Coliru 再一次

其他提示

你可以明确人数的数字,你需要输的 cpp_dec_float::str() 方法:

std::cout << std::scientific << test_num.str(75) << std::endl;
// output: 0.707106781186547524400844362104849039284835937688474036588339869
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top