在科学记数法打印cpp_dec_float没有尾随零 [英] Print cpp_dec_float in scientific notation without trailing zeros

查看:399
本文介绍了在科学记数法打印cpp_dec_float没有尾随零的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我用<一个href=\"http://www.boost.org/doc/libs/1_55_0/libs/multi$p$pcision/doc/html/boost_multi$p$pcision/tut/floats/cpp_dec_float.html\"相对=nofollow> cpp_dec_float 任意precision,它的伟大,但我有麻烦找出如何打印所有显著数字。

I'm using cpp_dec_float for arbitrary precision, and it's great, but I'm having trouble figuring out how to print all significant digits.

例如,有了这个code设置

For example, with this code to setup

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

mp_type test_num("7.0710678118654752440084436210484903928483593768847403658833986900e-01");

如果我简单地打印

and if I simply print with

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;

我得到<$c$c>7.0710678118654752440084436210484903928483593768847403658833986900000000000000000000000000000000000000e-01.我很高兴没有失去precision,但它不是很保守的空间。

I get 7.0710678118654752440084436210484903928483593768847403658833986900000000000000000000000000000000000000e-01. I'm happy not to lose the precision, but it's not very space conservative.

有没有办法去除尾随零,而不会丢失任何precision与现有的工具?如果没有,怎么能尾随零将从结果字符串中删除?

Is there a way to remove the trailing zeros without losing any precision with existing tools? If not, how can the trailing zeros be removed from the resultant string?

如果现有的工具可以用来满足我的意图,又怎能 cpp_dec_float 在不失去precision并移至一个字符串尾随零科学记数法输出?我只能找到流范例

If existing tools can be used to satisfy my intent, how can cpp_dec_float be output in scientific notation without lost precision and trailing zeros removed to a string? I can only find the stream examples.

更紧密

由于mockinterface,我非常接近。

Thanks to mockinterface, I'm much closer.

我已经改变了code这样:

I've changed the code to this:

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;

要具有潜在的无限长度;然而,这被打印

To have potentially unlimited length; however, this is printed:

7.0710678118654752440084436210484903928480e-01

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

Which is close but seems strange. In the source mockinterface so graciously pointed out to me, I found these lines

if(number_of_digits == 0)
    number_of_digits = cpp_dec_float_total_digits10;

这表明,我认为它应该考虑到所有显著的数字,基本上什么输出是因为长度不受限制。

which suggests to me that it should take into account all significant digits, basically outputting what was input because of the unlimited length.

我查了<一个href=\"http://$c$c.woboq.org/boost/boost/boost/multi$p$pcision/cpp_dec_float.hpp.html#_ZN5boost14multi$p$pcision8backends13cpp_dec_float28cpp_dec_float_total_digits10E\"相对=nofollow>为 cpp_dec_float_total_digits10 >,我无法确定究竟是什么;虽然,我没有找到这个code节,似乎定义它。

I checked the source for cpp_dec_float_total_digits10, and I am unable to determine exactly what it is; although, I did find this code section that seems to define it.

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 ::多precision :: cpp_dec_float :: STR()

推荐答案

这竟然是一个艰难的一个。

This turned out to be a tough one.

简短的故事是:没有在cpp_dec_float没有这样的功能。更糟的是,cpp_dec_float不跟踪的已设置显著的位数,所以没有廉价​​的方式找到打印的分数所需要的长度。

The short story is: there is no such functionality in cpp_dec_float. What's worse, cpp_dec_float doesn't track the number of significant digits that have been set, so there's no "cheap" way to find the length needed to print the fraction.

思路:


  • 有关一些边境情况下(例如123.000000000000001)人们可以采取的小数部分的整数部分+ LOG10的倒数的LOG10。这完全不能是一般适用的。

  • For some border cases (e.g. 123.000000000000001) one could take the log10 of the reciprocal of the the fractional part + log10 of the integer part. This completely fails to be generically applicable.

如果你想使用实现细节你可能会发现后端阵列中的'最后一个有人居住的'元素,并做数学。然而,这是涉及到pretty(需要修改 cpp_dec_float.hpp 和大量的测试)。

If you want to use implementation details you might find the 'last inhabited' element in the backend array, and do the maths. However, this is pretty involved (requires modifying cpp_dec_float.hpp and a lot of testing).

最后,我观察到,当前实施名为.str()显然会让的努力是有效的。在所有。

Finally, I observed that the current implementation for .str() clearly makes zero effort to be efficient. At all.

所以,所有的一切我有以下几点建议。无论

So all in all I have the following suggestions. Either


  1. 切换到 GMP 后端(如果你能负担得起)。注意

  1. switch to the gmp backend (if you can afford it). Note


  • 这不是一个十进制浮点重新presentation AFAICT

  • 这需要附加库(libgmp)被链接

  • gmp_float 确实的具有任意precision不过,

  • STR()实施的确实的考虑尾数零的意义

  • this is not a decimal float representation AFAICT
  • this requires an additional library (libgmp) to be linked
  • gmp_float does have arbitrary precision though, and
  • it's str() implementation does take into account the significance of zeroes in the mantissa

看它的 住在Coliru

See it Live On 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 而无需进一步的行动。

如果这不是一种选择,我只是后期处理的输出,去除尾随零:

If that's not an option, I'd just post-process the output, removing the trailing zeroes:

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 再次

See it Live On Coliru again

这篇关于在科学记数法打印cpp_dec_float没有尾随零的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆